diff --git a/SConstruct b/SConstruct index 938f08c4f..264158c2c 100644 --- a/SConstruct +++ b/SConstruct @@ -60,11 +60,12 @@ class ConfigureTests: comment_not_supported = '/* not supported */' __flags_Werror = {k:['-Werror'] for k in ['CXXFLAGS']} __empty_main_program = 'int a();int a(){return 0;}' + _cxx_conformance_cxx11 = 11 def __init__(self,msgprefix,user_settings): self.msgprefix = msgprefix self.user_settings = user_settings self.successful_flags = {} - self.__repeated_tests = {} + self.__cxx_conformance = None self.__automatic_compiler_tests = { '.cpp': self.check_cxx_works, } @@ -76,18 +77,6 @@ class ConfigureTests: if lines[-1].startswith("help:"): return lines[-1][5:] return None - def _may_repeat(f): - def wrap(self,*args,**kwargs): - try: - return self.__repeated_tests[f.__name__] - except KeyError as e: - pass - r = f(self,*args,**kwargs) - self.__repeated_tests[f.__name__] = r - return r - wrap.__name__ = 'repeat-wrap:' + f.__name__ - wrap.__doc__ = f.__doc__ - return wrap def _check_forced(self,context,name): return getattr(self.user_settings, 'sconf_%s' % name) def _check_macro(self,context,macro_name,macro_value,test,**kwargs): @@ -384,39 +373,38 @@ help:assume compiler supports __attribute__((warn_unused_result)) int a()__attribute_warn_unused_result; int a(){return 0;} """, msg='for function __attribute__((warn_unused_result))') - @_may_repeat @_implicit_test def check_cxx11(self,context): """ help:assume C++ compiler supports C++11 """ - for f in ['-std=gnu++11', '-std=gnu++0x', '-std=c++11', '-std=c++0x']: + return self._check_cxx_std_flag(context, ('-std=gnu++0x', '-std=c++0x'), self._cxx_conformance_cxx11) + def _check_cxx_std_flag(self,context,flags,level): + for f in flags: r = self.Compile(context, text=self.__empty_main_program, msg='whether C++ compiler accepts {f}'.format(f=f), successflags={'CXXFLAGS': [f]}) if r: - return r - return False - def __cxx11(f): - def wrap(self, context, *args, **kwargs): - return f(self,context,cxx11_check_result=self.check_cxx11(context),*args,**kwargs) - wrap.__name__ += ':' + f.__name__ - return wrap - def __skip_missing_cxx11(self,cxx11_check_result): - if cxx11_check_result: - return None - return 'no C++11 support' + return level + return 0 + def Cxx11Compile(self,context,*args,**kwargs): + kwargs.setdefault('skipped', self.__skip_missing_cxx_std(context, self._cxx_conformance_cxx11, 'no C++11 support')) + return self.Compile(context,*args,**kwargs) + def __skip_missing_cxx_std(self,context,level,text): + if self.__cxx_conformance is None: + self.__cxx_conformance = self.check_cxx11(context) + if self.__cxx_conformance < level: + return text @_implicit_test def check_boost_array(self,context,f): """ help:assume Boost.Array works """ return self.Compile(context, text=f, msg='for Boost.Array', successflags={'CPPDEFINES' : ['DXX_HAVE_BOOST_ARRAY']}) - @__cxx11 @_implicit_test - def check_cxx_array(self,context,f,cxx11_check_result): + def check_cxx_array(self,context,f): """ help:assume works """ - return self.Compile(context, text=f, msg='for ', skipped=self.__skip_missing_cxx11(cxx11_check_result), successflags={'CPPDEFINES' : ['DXX_HAVE_CXX_ARRAY']}) + return self.Cxx11Compile(context, text=f, msg='for ', successflags={'CPPDEFINES' : ['DXX_HAVE_CXX_ARRAY']}) @_implicit_test def check_cxx_tr1_array(self,context,f): """ @@ -432,20 +420,19 @@ void a();void a(){arrayb;b[0]=1;} how = self.check_cxx_array(context, f) or self.check_boost_array(context, f) or self.check_cxx_tr1_array(context, f) if not how: raise SCons.Errors.StopError("C++ compiler does not support or Boost.Array or .") - @__cxx11 @_custom_test - def check_cxx11_function_auto(self,context,cxx11_check_result): + def check_cxx11_function_auto(self,context): """ help:assume compiler supports C++11 function declarator syntax """ f = ''' auto f()->int; ''' - if self.Compile(context, text=f, msg='for C++11 function declarator syntax', skipped=self.__skip_missing_cxx11(cxx11_check_result)): - context.sconf.Define('DXX_HAVE_CXX11_FUNCTION_AUTO') - def _check_static_assert_method(self,context,msg,f,testflags={},**kwargs): - return self.Compile(context, text=f % 'true', msg=msg % 'true', testflags=testflags, **kwargs) and \ - self.Compile(context, text=f % 'false', msg=msg % 'false', expect_failure=True, successflags=testflags, **kwargs) + if not self.Cxx11Compile(context, text=f, msg='for C++11 function declarator syntax'): + raise SCons.Errors.StopError("C++ compiler does not support C++11 function declarator syntax.") + def _check_static_assert_method(self,context,msg,f,testflags={},_Compile=Compile,**kwargs): + return _Compile(self, context, text=f % 'true', msg=msg % 'true', testflags=testflags, **kwargs) and \ + _Compile(self, context, text=f % 'false', msg=msg % 'false', expect_failure=True, successflags=testflags, **kwargs) @_implicit_test def check_boost_static_assert(self,context,f): """ @@ -458,13 +445,12 @@ help:assume Boost.StaticAssert works help:assume C typedef-based static assertion works """ return self._check_static_assert_method(context, 'for C typedef static assertion when %s', f, testflags={'CPPDEFINES' : ['DXX_HAVE_C_TYPEDEF_STATIC_ASSERT']}) - @__cxx11 @_implicit_test - def check_cxx11_static_assert(self,context,f,cxx11_check_result): + def check_cxx11_static_assert(self,context,f): """ help:assume compiler supports C++ intrinsic static_assert """ - return self._check_static_assert_method(context, 'for C++11 intrinsic static_assert when %s', f, testflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_STATIC_ASSERT']}, skipped=self.__skip_missing_cxx11(cxx11_check_result)) + return self._check_static_assert_method(context, 'for C++11 intrinsic static_assert when %s', f, testflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_STATIC_ASSERT']}, _Compile=ConfigureTests.Cxx11Compile) @_custom_test def _check_static_assert(self,context): f = ''' @@ -480,13 +466,12 @@ static_assert(%s, ""); help:assume Boost.TypeTraits works """ return self.Compile(context, text=f, msg='for Boost.TypeTraits', ext='.cpp', successflags={'CPPDEFINES' : ['DXX_HAVE_BOOST_TYPE_TRAITS']}) - @__cxx11 @_implicit_test - def check_cxx11_type_traits(self,context,f,cxx11_check_result): + def check_cxx11_type_traits(self,context,f): """ help:assume works """ - return self.Compile(context, text=f, msg='for ', ext='.cpp', skipped=self.__skip_missing_cxx11(cxx11_check_result), successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_TYPE_TRAITS']}) + return self.Cxx11Compile(context, text=f, msg='for ', ext='.cpp', successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_TYPE_TRAITS']}) @_custom_test def _check_type_traits(self,context): f = ''' @@ -502,10 +487,9 @@ typedef tt::conditional::type b; help:assume Boost.Foreach works """ return self.Compile(context, text=text, msg='for Boost.Foreach', successflags={'CPPDEFINES' : ['DXX_HAVE_BOOST_FOREACH']}) - @__cxx11 @_implicit_test - def check_cxx11_range_for(self,context,text,cxx11_check_result): - return self.Compile(context, text=text, msg='for C++11 range-based for', skipped=self.__skip_missing_cxx11(cxx11_check_result), successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_RANGE_FOR']}) + def check_cxx11_range_for(self,context,text): + return self.Cxx11Compile(context, text=text, msg='for C++11 range-based for', successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_RANGE_FOR']}) @_custom_test def _check_range_based_for(self,context): f = ''' @@ -537,42 +521,39 @@ void a(){int b[2];range_for(int&c,b)c=0;} context.Display('if used at least %u time%s\n' % (count, 's' if count > 1 else '')) if not self.check_pch(context): raise SCons.Errors.StopError("C++ compiler does not support pre-compiled headers.") - @__cxx11 @_custom_test - def check_cxx11_explicit_bool(self,context,cxx11_check_result): + def check_cxx11_explicit_bool(self,context): """ help:assume compiler supports explicit operator bool """ f = ''' struct A{explicit operator bool();}; ''' - r = self.Compile(context, text=f, msg='for explicit operator bool', skipped=self.__skip_missing_cxx11(cxx11_check_result)) + r = self.Cxx11Compile(context, text=f, msg='for explicit operator bool') macro_name = 'dxx_explicit_operator_bool' if r: context.sconf.Define(macro_name, 'explicit') context.sconf.Define('DXX_HAVE_EXPLICIT_OPERATOR_BOOL') else: context.sconf.Define(macro_name, self.comment_not_supported) - @__cxx11 @_custom_test - def check_cxx11_explicit_delete(self,context,cxx11_check_result): + def check_cxx11_explicit_delete(self,context): """ help:assume compiler supports explicitly deleted functions """ f = ''' int a()=delete; ''' - r = self.Compile(context, text=f, msg='for explicitly deleted functions', skipped=self.__skip_missing_cxx11(cxx11_check_result)) + r = self.Cxx11Compile(context, text=f, msg='for explicitly deleted functions') macro_name = 'DXX_CXX11_EXPLICIT_DELETE' if r: context.sconf.Define(macro_name, '=delete') context.sconf.Define('DXX_HAVE_CXX11_EXPLICIT_DELETE') else: context.sconf.Define(macro_name, self.comment_not_supported) - @__cxx11 @_implicit_test - def check_cxx11_free_begin(self,context,text,cxx11_check_result): - return self.Compile(context, text=text, msg='for C++11 functions begin(), end()', skipped=self.__skip_missing_cxx11(cxx11_check_result), successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_BEGIN']}) + def check_cxx11_free_begin(self,context,text): + return self.Cxx11Compile(context, text=text, msg='for C++11 functions begin(), end()', successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_BEGIN']}) @_implicit_test def check_boost_free_begin(self,context,text): return self.Compile(context, text=text, msg='for Boost.Range functions begin(), end()', successflags={'CPPDEFINES' : ['DXX_HAVE_BOOST_BEGIN']}) @@ -601,10 +582,9 @@ int c() { ''' if not self.check_cxx11_free_begin(context, text=f) and not self.check_boost_free_begin(context, text=f): raise SCons.Errors.StopError("C++ compiler does not support free functions begin() and end().") - @__cxx11 @_implicit_test - def check_cxx11_addressof(self,context,text,cxx11_check_result): - return self.Compile(context, text=text, msg='for C++11 function addressof()', skipped=self.__skip_missing_cxx11(cxx11_check_result), successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_ADDRESSOF']}) + def check_cxx11_addressof(self,context,text): + return self.Cxx11Compile(context, text=text, msg='for C++11 function addressof()', successflags={'CPPDEFINES' : ['DXX_HAVE_CXX11_ADDRESSOF']}) @_implicit_test def check_boost_addressof(self,context,text): return self.Compile(context, text=text, msg='for Boost.Utility function addressof()', successflags={'CPPDEFINES' : ['DXX_HAVE_BOOST_ADDRESSOF']}) @@ -622,21 +602,19 @@ A *a(A &b) { ''' if not self.check_cxx11_addressof(context, text=f) and not self.check_boost_addressof(context, text=f): raise SCons.Errors.StopError("C++ compiler does not support free function addressof().") - @__cxx11 @_implicit_test - def check_cxx11_inherit_constructor(self,context,text,fmtargs,cxx11_check_result): + def check_cxx11_inherit_constructor(self,context,text,fmtargs): """ help:assume compiler supports inheriting constructors """ macro_value = '''\\ typedef B,##__VA_ARGS__ _dxx_constructor_base_type;\\ using _dxx_constructor_base_type::_dxx_constructor_base_type;''' - if self.Compile(context, text=text.format(macro_value=macro_value, **fmtargs), msg='for C++11 inherited constructors', skipped=self.__skip_missing_cxx11(cxx11_check_result)): + if self.Cxx11Compile(context, text=text.format(macro_value=macro_value, **fmtargs), msg='for C++11 inherited constructors'): return macro_value return None - @__cxx11 @_implicit_test - def check_cxx11_variadic_forward_constructor(self,context,text,fmtargs,cxx11_check_result): + def check_cxx11_variadic_forward_constructor(self,context,text,fmtargs): """ help:assume compiler supports variadic template-based constructor forwarding """ @@ -645,7 +623,7 @@ help:assume compiler supports variadic template-based constructor forwarding D(Args&&... args) : \\ B,##__VA_ARGS__(std::forward(args)...) {} ''' - if self.Compile(context, text='#include \n' + text.format(macro_value=macro_value, **fmtargs), msg='for C++11 variadic templates on constructors', skipped=self.__skip_missing_cxx11(cxx11_check_result)): + if self.Cxx11Compile(context, text='#include \n' + text.format(macro_value=macro_value, **fmtargs), msg='for C++11 variadic templates on constructors'): return macro_value return None @_custom_test