Use SConscript configure support to probe for format_arg attribute
This commit is contained in:
parent
1b912463d3
commit
2215c0848d
149
SConstruct
149
SConstruct
|
@ -24,6 +24,123 @@ def checkEndian():
|
||||||
return "big"
|
return "big"
|
||||||
return "unknown"
|
return "unknown"
|
||||||
|
|
||||||
|
class ConfigureTests:
|
||||||
|
class Collector:
|
||||||
|
def __init__(self):
|
||||||
|
self.tests = []
|
||||||
|
def __call__(self,f):
|
||||||
|
self.tests.append(f.__name__)
|
||||||
|
return f
|
||||||
|
_implicit_test = Collector()
|
||||||
|
_custom_test = Collector()
|
||||||
|
implicit_tests = _implicit_test.tests
|
||||||
|
custom_tests = _custom_test.tests
|
||||||
|
comment_not_supported = '/* not supported */'
|
||||||
|
__flags_Werror = {k:['-Werror'] for k in ['CFLAGS', 'CXXFLAGS']}
|
||||||
|
__empty_main_program = 'int main(){return 0;}'
|
||||||
|
def __init__(self,msgprefix,user_settings):
|
||||||
|
self.msgprefix = msgprefix
|
||||||
|
self.user_settings = user_settings
|
||||||
|
self.__repeated_tests = {}
|
||||||
|
self.__automatic_compiler_tests = {
|
||||||
|
'.c': self.check_cc_works,
|
||||||
|
}
|
||||||
|
@classmethod
|
||||||
|
def describe(cls,name):
|
||||||
|
f = getattr(cls, name)
|
||||||
|
if f.__doc__:
|
||||||
|
lines = f.__doc__.rstrip().split('\n')
|
||||||
|
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):
|
||||||
|
r = self.Compile(context, text="""
|
||||||
|
#define {macro_name} {macro_value}
|
||||||
|
{test}
|
||||||
|
""".format(macro_name=macro_name, macro_value=macro_value, test=test), **kwargs)
|
||||||
|
if r:
|
||||||
|
context.sconf.Define(macro_name, macro_value)
|
||||||
|
else:
|
||||||
|
context.sconf.Define(macro_name, self.comment_not_supported)
|
||||||
|
def __compiler_test_already_done(self,context):
|
||||||
|
pass
|
||||||
|
def Compile(self,context,text,msg,ext='.c',successflags={},skipped=None,successmsg=None,failuremsg=None):
|
||||||
|
self.__automatic_compiler_tests.pop(ext, self.__compiler_test_already_done)(context)
|
||||||
|
context.Message('%s: checking %s...' % (self.msgprefix, msg))
|
||||||
|
if skipped is not None:
|
||||||
|
context.Result('(skipped){skipped}'.format(skipped=skipped))
|
||||||
|
return
|
||||||
|
frame = None
|
||||||
|
try:
|
||||||
|
1//0
|
||||||
|
except ZeroDivisionError:
|
||||||
|
frame = sys.exc_info()[2].tb_frame.f_back
|
||||||
|
while frame is not None:
|
||||||
|
co_name = frame.f_code.co_name
|
||||||
|
if co_name[0:6] == 'check_':
|
||||||
|
forced = self._check_forced(context, co_name[6:])
|
||||||
|
if forced is not None:
|
||||||
|
context.Result('(forced){forced}'.format(forced='yes' if forced else 'no'))
|
||||||
|
return forced
|
||||||
|
break
|
||||||
|
frame = frame.f_back
|
||||||
|
env_flags = {k: context.env[k] for k in successflags.keys()}
|
||||||
|
context.env.Append(**successflags)
|
||||||
|
caller_modified_env_flags = {k: context.env[k] for k in self.__flags_Werror.keys()}
|
||||||
|
# Always pass -Werror
|
||||||
|
context.env.Append(**self.__flags_Werror)
|
||||||
|
# Force verbose output to sconf.log
|
||||||
|
cc_env_strings = {}
|
||||||
|
for k in ['CCCOMSTR', 'CXXCOMSTR']:
|
||||||
|
try:
|
||||||
|
cc_env_strings[k] = context.env[k]
|
||||||
|
del context.env[k]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
r = context.TryCompile(text + '\n', ext)
|
||||||
|
# Restore potential quiet build options
|
||||||
|
context.env.Replace(**cc_env_strings)
|
||||||
|
context.Result((successmsg if r else failuremsg) or r)
|
||||||
|
# On success, revert to base flags + successflags
|
||||||
|
# On failure, revert to base flags
|
||||||
|
if r:
|
||||||
|
context.env.Replace(**caller_modified_env_flags)
|
||||||
|
else:
|
||||||
|
context.env.Replace(**env_flags)
|
||||||
|
return r
|
||||||
|
@_may_repeat
|
||||||
|
@_implicit_test
|
||||||
|
def check_cc_works(self,context):
|
||||||
|
"""
|
||||||
|
help:assume C compiler works
|
||||||
|
"""
|
||||||
|
if not self.Compile(context, text=self.__empty_main_program, msg='whether C compiler works'):
|
||||||
|
raise SCons.Errors.StopError("C compiler does not work.")
|
||||||
|
@_custom_test
|
||||||
|
def check_attribute_format_arg(self,context):
|
||||||
|
"""
|
||||||
|
help:assume compiler supports __attribute__((format_arg))
|
||||||
|
"""
|
||||||
|
macro_name = '__attribute_format_arg(A)'
|
||||||
|
macro_value = '__attribute__((format_arg(A)))'
|
||||||
|
self._check_macro(context,macro_name=macro_name,macro_value=macro_value,test="""
|
||||||
|
char*a(char*)__attribute_format_arg(1);
|
||||||
|
""", msg='for function __attribute__((format_arg))')
|
||||||
|
|
||||||
class LazyObjectConstructor:
|
class LazyObjectConstructor:
|
||||||
def __lazy_objects(self,name,source):
|
def __lazy_objects(self,name,source):
|
||||||
try:
|
try:
|
||||||
|
@ -117,6 +234,12 @@ class DXXCommon(LazyObjectConstructor):
|
||||||
return EnumVariable(key, help, default, allowed_values)
|
return EnumVariable(key, help, default, allowed_values)
|
||||||
def _options(self):
|
def _options(self):
|
||||||
return (
|
return (
|
||||||
|
{
|
||||||
|
'variable': BoolVariable,
|
||||||
|
'arguments': [
|
||||||
|
('sconf_%s' % name[6:], None, ConfigureTests.describe(name) or ('assume result of %s' % name)) for name in ConfigureTests.implicit_tests + ConfigureTests.custom_tests
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'variable': BoolVariable,
|
'variable': BoolVariable,
|
||||||
'arguments': (
|
'arguments': (
|
||||||
|
@ -354,7 +477,7 @@ class DXXCommon(LazyObjectConstructor):
|
||||||
self.env.Append(CCFLAGS = ['-Wall', '-Wundef', '-Werror=undef', '-funsigned-char', '-Werror=implicit-int', '-Werror=implicit-function-declaration', '-pthread'])
|
self.env.Append(CCFLAGS = ['-Wall', '-Wundef', '-Werror=undef', '-funsigned-char', '-Werror=implicit-int', '-Werror=implicit-function-declaration', '-pthread'])
|
||||||
self.env.Append(CFLAGS = ['-std=gnu99'])
|
self.env.Append(CFLAGS = ['-std=gnu99'])
|
||||||
self.env.Append(CPPDEFINES = ['NETWORK'])
|
self.env.Append(CPPDEFINES = ['NETWORK'])
|
||||||
self.env.Append(CPPPATH = ['common/include', 'common/main', '.'])
|
self.env.Append(CPPPATH = ['common/include', 'common/main', '.', self.user_settings.builddir])
|
||||||
if (self.user_settings.editor == 1):
|
if (self.user_settings.editor == 1):
|
||||||
self.env.Append(CPPPATH = ['common/include/editor'])
|
self.env.Append(CPPPATH = ['common/include/editor'])
|
||||||
# Get traditional compiler environment variables
|
# Get traditional compiler environment variables
|
||||||
|
@ -746,6 +869,7 @@ class DXXProgram(DXXCommon):
|
||||||
self.prepare_environment()
|
self.prepare_environment()
|
||||||
self.check_endian()
|
self.check_endian()
|
||||||
self.process_user_settings()
|
self.process_user_settings()
|
||||||
|
self.configure_environment()
|
||||||
self.register_program()
|
self.register_program()
|
||||||
|
|
||||||
def prepare_environment(self):
|
def prepare_environment(self):
|
||||||
|
@ -789,6 +913,29 @@ class DXXProgram(DXXCommon):
|
||||||
|
|
||||||
env.Append(CPPDEFINES = [('SHAREPATH', '\\"' + str(self.user_settings.sharepath) + '\\"')])
|
env.Append(CPPDEFINES = [('SHAREPATH', '\\"' + str(self.user_settings.sharepath) + '\\"')])
|
||||||
|
|
||||||
|
def configure_environment(self):
|
||||||
|
fs = SCons.Node.FS.get_default_fs()
|
||||||
|
builddir = fs.Dir(self.user_settings.builddir or '.')
|
||||||
|
tests = ConfigureTests(self.program_message_prefix, self.user_settings)
|
||||||
|
log_file=fs.File('sconf.log', builddir)
|
||||||
|
conf = self.env.Configure(custom_tests = {
|
||||||
|
k:getattr(tests, k) for k in tests.custom_tests
|
||||||
|
},
|
||||||
|
conf_dir=fs.Dir('.sconf_temp', builddir),
|
||||||
|
log_file=log_file,
|
||||||
|
config_h=fs.File('dxxsconf.h', builddir),
|
||||||
|
clean=False,
|
||||||
|
help=False
|
||||||
|
)
|
||||||
|
if not conf.env:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
for k in tests.custom_tests:
|
||||||
|
getattr(conf, k)()
|
||||||
|
except SCons.Errors.StopError as e:
|
||||||
|
raise SCons.Errors.StopError(e.args[0] + ' See {log_file} for details.'.format(log_file=log_file), *e.args[1:])
|
||||||
|
self.env = conf.Finish()
|
||||||
|
|
||||||
def _register_program(self,dxxstr,program_specific_objects=[]):
|
def _register_program(self,dxxstr,program_specific_objects=[]):
|
||||||
env = self.env
|
env = self.env
|
||||||
exe_target = os.path.join(self.srcdir, self.target)
|
exe_target = os.path.join(self.srcdir, self.target)
|
||||||
|
|
|
@ -21,6 +21,8 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
||||||
#ifndef _TEXT_H
|
#ifndef _TEXT_H
|
||||||
#define _TEXT_H
|
#define _TEXT_H
|
||||||
|
|
||||||
|
#include "dxxsconf.h"
|
||||||
|
|
||||||
//Symbolic constants for all the strings
|
//Symbolic constants for all the strings
|
||||||
|
|
||||||
#define TXT_NEW_GAME dxx_gettext(0, "New game")
|
#define TXT_NEW_GAME dxx_gettext(0, "New game")
|
||||||
|
@ -1276,6 +1278,7 @@ void free_text();
|
||||||
extern char *Text_string[N_TEXT_STRINGS];
|
extern char *Text_string[N_TEXT_STRINGS];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline char *dxx_gettext(unsigned expr, const char *fmt) __attribute_format_arg(2);
|
||||||
static inline char *dxx_gettext(unsigned expr, const char *fmt)
|
static inline char *dxx_gettext(unsigned expr, const char *fmt)
|
||||||
{
|
{
|
||||||
#ifdef USE_BUILTIN_ENGLISH_TEXT_STRINGS
|
#ifdef USE_BUILTIN_ENGLISH_TEXT_STRINGS
|
||||||
|
|
Loading…
Reference in a new issue