Changeset 7bdcc45 in mainline for tools


Ignore:
Timestamp:
2010-12-16T16:38:49Z (15 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
7837101
Parents:
8e58f94 (diff), eb221e5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge mainline changes.

Location:
tools
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • tools/autotool.py

    r8e58f94 r7bdcc45  
    4949
    5050PACKAGE_BINUTILS = "usually part of binutils"
    51 PACKAGE_GCC = "preferably version 4.4.3 or newer"
     51PACKAGE_GCC = "preferably version 4.5.1 or newer"
    5252PACKAGE_CROSS = "use tools/toolchain.sh to build the cross-compiler toolchain"
    5353
    5454COMPILER_FAIL = "The compiler is probably not capable to compile HelenOS."
    55 
    56 PROBE_HEAD = """#define AUTOTOOL_DECLARE(category, subcategory, tag, name, value) \\
     55COMPILER_WARNING = "The compilation of HelenOS might fail."
     56
     57PROBE_HEAD = """#define AUTOTOOL_DECLARE(category, subcategory, tag, name, strc, conc, value) \\
    5758        asm volatile ( \\
    58                 "AUTOTOOL_DECLARE\\t" category "\\t" subcategory "\\t" tag "\\t" name "\\t%[val]\\n" \\
     59                "AUTOTOOL_DECLARE\\t" category "\\t" subcategory "\\t" tag "\\t" name "\\t" strc "\\t" conc "\\t%[val]\\n" \\
    5960                : \\
    6061                : [val] "n" (value) \\
    6162        )
    6263
    63 #define DECLARE_INTSIZE(tag, type) \\
    64         AUTOTOOL_DECLARE("intsize", "unsigned", tag, #type, sizeof(unsigned type)); \\
    65         AUTOTOOL_DECLARE("intsize", "signed", tag, #type, sizeof(signed type))
     64#define STRING(arg)      STRING_ARG(arg)
     65#define STRING_ARG(arg)  #arg
     66
     67#define DECLARE_BUILTIN_TYPE(tag, type) \\
     68        AUTOTOOL_DECLARE("builtin", "", tag, STRING(type), "", "", sizeof(type));
     69
     70#define DECLARE_INTSIZE(tag, type, strc, conc) \\
     71        AUTOTOOL_DECLARE("intsize", "unsigned", tag, #type, strc, conc, sizeof(unsigned type)); \\
     72        AUTOTOOL_DECLARE("intsize", "signed", tag, #type, strc, conc, sizeof(signed type));
    6673
    6774int main(int argc, char *argv[])
    6875{
     76#ifdef __SIZE_TYPE__
     77        DECLARE_BUILTIN_TYPE("size", __SIZE_TYPE__);
     78#endif
     79#ifdef __WCHAR_TYPE__
     80        DECLARE_BUILTIN_TYPE("wchar", __WCHAR_TYPE__);
     81#endif
     82#ifdef __WINT_TYPE__
     83        DECLARE_BUILTIN_TYPE("wint", __WINT_TYPE__);
     84#endif
    6985"""
    7086
     
    96112       
    97113        sys.exit(1)
     114
     115def print_warning(msg):
     116        "Print a bold error message"
     117       
     118        sys.stderr.write("\n")
     119        sys.stderr.write("######################################################################\n")
     120        sys.stderr.write("HelenOS build sanity check warning:\n")
     121        sys.stderr.write("\n")
     122        sys.stderr.write("%s\n" % "\n".join(msg))
     123        sys.stderr.write("######################################################################\n")
     124        sys.stderr.write("\n")
     125       
     126        time.sleep(5)
    98127
    99128def sandbox_enter():
     
    186215        check_app([common['STRIP'], "--version"], "GNU strip", details)
    187216
     217def decode_value(value):
     218        "Decode integer value"
     219       
     220        base = 10
     221       
     222        if ((value.startswith('$')) or (value.startswith('#'))):
     223                value = value[1:]
     224       
     225        if (value.startswith('0x')):
     226                value = value[2:]
     227                base = 16
     228       
     229        return int(value, base)
     230
    188231def probe_compiler(common, sizes):
    189232        "Generate, compile and parse probing source"
     
    195238       
    196239        for typedef in sizes:
    197                 outf.write("\tDECLARE_INTSIZE(\"%s\", %s);\n" % (typedef['tag'], typedef['type']))
     240                outf.write("\tDECLARE_INTSIZE(\"%s\", %s, %s, %s);\n" % (typedef['tag'], typedef['type'], typedef['strc'], typedef['conc']))
    198241       
    199242        outf.write(PROBE_TAIL)
     
    231274        signed_tags = {}
    232275       
     276        unsigned_strcs = {}
     277        signed_strcs = {}
     278       
     279        unsigned_concs = {}
     280        signed_concs = {}
     281       
     282        builtins = {}
     283       
    233284        for j in range(len(lines)):
    234285                tokens = lines[j].strip().split("\t")
     
    236287                if (len(tokens) > 0):
    237288                        if (tokens[0] == "AUTOTOOL_DECLARE"):
    238                                 if (len(tokens) < 5):
     289                                if (len(tokens) < 7):
    239290                                        print_error(["Malformed declaration in \"%s\" on line %s." % (PROBE_OUTPUT, j), COMPILER_FAIL])
    240291                               
     
    243294                                tag = tokens[3]
    244295                                name = tokens[4]
    245                                 value = tokens[5]
     296                                strc = tokens[5]
     297                                conc = tokens[6]
     298                                value = tokens[7]
    246299                               
    247300                                if (category == "intsize"):
    248                                         base = 10
    249                                        
    250                                         if ((value.startswith('$')) or (value.startswith('#'))):
    251                                                 value = value[1:]
    252                                        
    253                                         if (value.startswith('0x')):
    254                                                 value = value[2:]
    255                                                 base = 16
    256                                        
    257301                                        try:
    258                                                 value_int = int(value, base)
     302                                                value_int = decode_value(value)
    259303                                        except:
    260304                                                print_error(["Integer value expected in \"%s\" on line %s." % (PROBE_OUTPUT, j), COMPILER_FAIL])
    261305                                       
    262306                                        if (subcategory == "unsigned"):
    263                                                 unsigned_sizes[name] = value_int
     307                                                unsigned_sizes[value_int] = name
    264308                                                unsigned_tags[tag] = value_int
     309                                                unsigned_strcs[value_int] = strc
     310                                                unsigned_concs[value_int] = conc
    265311                                        elif (subcategory == "signed"):
    266                                                 signed_sizes[name] = value_int
     312                                                signed_sizes[value_int] = name
    267313                                                signed_tags[tag] = value_int
     314                                                signed_strcs[value_int] = strc
     315                                                signed_concs[value_int] = conc
    268316                                        else:
    269317                                                print_error(["Unexpected keyword \"%s\" in \"%s\" on line %s." % (subcategory, PROBE_OUTPUT, j), COMPILER_FAIL])
    270        
    271         return {'unsigned_sizes' : unsigned_sizes, 'signed_sizes' : signed_sizes, 'unsigned_tags': unsigned_tags, 'signed_tags': signed_tags}
    272 
    273 def detect_uints(probe, bytes):
     318                               
     319                                if (category == "builtin"):
     320                                        try:
     321                                                value_int = decode_value(value)
     322                                        except:
     323                                                print_error(["Integer value expected in \"%s\" on line %s." % (PROBE_OUTPUT, j), COMPILER_FAIL])
     324                                       
     325                                        builtins[tag] = {'name': name, 'value': value_int}
     326       
     327        return {'unsigned_sizes': unsigned_sizes, 'signed_sizes': signed_sizes, 'unsigned_tags': unsigned_tags, 'signed_tags': signed_tags, 'unsigned_strcs': unsigned_strcs, 'signed_strcs': signed_strcs, 'unsigned_concs': unsigned_concs, 'signed_concs': signed_concs, 'builtins': builtins}
     328
     329def detect_uints(probe, bytes, tags):
    274330        "Detect correct types for fixed-size integer types"
    275331       
     
    278334       
    279335        for b in bytes:
     336                if (not b in probe['unsigned_sizes']):
     337                        print_error(['Unable to find appropriate unsigned integer type for %u bytes' % b,
     338                                     COMPILER_FAIL])
     339               
     340                if (not b in probe['signed_sizes']):
     341                        print_error(['Unable to find appropriate signed integer type for %u bytes' % b,
     342                                     COMPILER_FAIL])
     343               
     344                if (not b in probe['unsigned_strcs']):
     345                        print_error(['Unable to find appropriate unsigned printf formatter for %u bytes' % b,
     346                                     COMPILER_FAIL])
     347               
     348                if (not b in probe['signed_strcs']):
     349                        print_error(['Unable to find appropriate signed printf formatter for %u bytes' % b,
     350                                     COMPILER_FAIL])
     351               
     352                if (not b in probe['unsigned_concs']):
     353                        print_error(['Unable to find appropriate unsigned literal macro for %u bytes' % b,
     354                                     COMPILER_FAIL])
     355               
     356                if (not b in probe['signed_concs']):
     357                        print_error(['Unable to find appropriate signed literal macro for %u bytes' % b,
     358                                     COMPILER_FAIL])
     359               
     360                typedefs.append({'oldtype': "unsigned %s" % probe['unsigned_sizes'][b], 'newtype': "uint%u_t" % (b * 8)})
     361                typedefs.append({'oldtype': "signed %s" % probe['signed_sizes'][b], 'newtype': "int%u_t" % (b * 8)})
     362               
     363                macros.append({'oldmacro': "\"%so\"" % probe['unsigned_strcs'][b], 'newmacro': "PRIo%u" % (b * 8)})
     364                macros.append({'oldmacro': "\"%su\"" % probe['unsigned_strcs'][b], 'newmacro': "PRIu%u" % (b * 8)})
     365                macros.append({'oldmacro': "\"%sx\"" % probe['unsigned_strcs'][b], 'newmacro': "PRIx%u" % (b * 8)})
     366                macros.append({'oldmacro': "\"%sX\"" % probe['unsigned_strcs'][b], 'newmacro': "PRIX%u" % (b * 8)})
     367                macros.append({'oldmacro': "\"%sd\"" % probe['signed_strcs'][b], 'newmacro': "PRId%u" % (b * 8)})
     368               
     369                name = probe['unsigned_concs'][b]
     370                if ((name.startswith('@')) or (name == "")):
     371                        macros.append({'oldmacro': "c ## U", 'newmacro': "UINT%u_C(c)" % (b * 8)})
     372                else:
     373                        macros.append({'oldmacro': "c ## U%s" % name, 'newmacro': "UINT%u_C(c)" % (b * 8)})
     374               
     375                name = probe['unsigned_concs'][b]
     376                if ((name.startswith('@')) or (name == "")):
     377                        macros.append({'oldmacro': "c", 'newmacro': "INT%u_C(c)" % (b * 8)})
     378                else:
     379                        macros.append({'oldmacro': "c ## %s" % name, 'newmacro': "INT%u_C(c)" % (b * 8)})
     380       
     381        for tag in tags:
     382                newmacro = "U%s" % tag
     383                if (not tag in probe['unsigned_tags']):
     384                        print_error(['Unable to find appropriate size macro for %s' % newmacro,
     385                                     COMPILER_FAIL])
     386               
     387                oldmacro = "UINT%s" % (probe['unsigned_tags'][tag] * 8)
     388                macros.append({'oldmacro': "%s_MIN" % oldmacro, 'newmacro': "%s_MIN" % newmacro})
     389                macros.append({'oldmacro': "%s_MAX" % oldmacro, 'newmacro': "%s_MAX" % newmacro})
     390               
     391                newmacro = tag
     392                if (not tag in probe['unsigned_tags']):
     393                        print_error(['Unable to find appropriate size macro for %s' % newmacro,
     394                                     COMPILER_FAIL])
     395               
     396                oldmacro = "INT%s" % (probe['signed_tags'][tag] * 8)
     397                macros.append({'oldmacro': "%s_MIN" % oldmacro, 'newmacro': "%s_MIN" % newmacro})
     398                macros.append({'oldmacro': "%s_MAX" % oldmacro, 'newmacro': "%s_MAX" % newmacro})
     399       
     400        fnd = True
     401       
     402        if (not 'wchar' in probe['builtins']):
     403                print_warning(['The compiler does not provide the macro __WCHAR_TYPE__',
     404                               'for defining the compiler-native type wchar_t. We are',
     405                               'forced to define wchar_t as a hardwired type int32_t.',
     406                               COMPILER_WARNING])
    280407                fnd = False
    281                 newtype = "uint%s_t" % (b * 8)
    282                
    283                 for name, value in probe['unsigned_sizes'].items():
    284                         if (value == b):
    285                                 oldtype = "unsigned %s" % name
    286                                 typedefs.append({'oldtype' : oldtype, 'newtype' : newtype})
    287                                 fnd = True
    288                                 break
    289                
    290                 if (not fnd):
    291                         print_error(['Unable to find appropriate integer type for %s' % newtype,
    292                                      COMPILER_FAIL])
    293                
    294                
     408       
     409        if (probe['builtins']['wchar']['value'] != 4):
     410                print_warning(['The compiler provided macro __WCHAR_TYPE__ for defining',
     411                               'the compiler-native type wchar_t is not compliant with',
     412                               'HelenOS. We are forced to define wchar_t as a hardwired',
     413                               'type int32_t.',
     414                               COMPILER_WARNING])
    295415                fnd = False
    296                 newtype = "int%s_t" % (b * 8)
    297                
    298                 for name, value in probe['signed_sizes'].items():
    299                         if (value == b):
    300                                 oldtype = "signed %s" % name
    301                                 typedefs.append({'oldtype' : oldtype, 'newtype' : newtype})
    302                                 fnd = True
    303                                 break
    304                
    305                 if (not fnd):
    306                         print_error(['Unable to find appropriate integer type for %s' % newtype,
    307                                      COMPILER_FAIL])
    308        
    309         for tag in ['CHAR', 'SHORT', 'INT', 'LONG', 'LLONG']:
    310                 fnd = False;
    311                 newmacro = "U%s" % tag
    312                
    313                 for name, value in probe['unsigned_tags'].items():
    314                         if (name == tag):
    315                                 oldmacro = "UINT%s" % (value * 8)
    316                                 macros.append({'oldmacro': "%s_MIN" % oldmacro, 'newmacro': "%s_MIN" % newmacro})
    317                                 macros.append({'oldmacro': "%s_MAX" % oldmacro, 'newmacro': "%s_MAX" % newmacro})
    318                                 fnd = True
    319                                 break
    320                
    321                 if (not fnd):
    322                         print_error(['Unable to find appropriate size macro for %s' % newmacro,
    323                                      COMPILER_FAIL])
    324                
    325                 fnd = False;
    326                 newmacro = tag
    327                
    328                 for name, value in probe['signed_tags'].items():
    329                         if (name == tag):
    330                                 oldmacro = "INT%s" % (value * 8)
    331                                 macros.append({'oldmacro': "%s_MIN" % oldmacro, 'newmacro': "%s_MIN" % newmacro})
    332                                 macros.append({'oldmacro': "%s_MAX" % oldmacro, 'newmacro': "%s_MAX" % newmacro})
    333                                 fnd = True
    334                                 break
    335                
    336                 if (not fnd):
    337                         print_error(['Unable to find appropriate size macro for %s' % newmacro,
    338                                      COMPILER_FAIL])
     416       
     417        if (not fnd):
     418                macros.append({'oldmacro': "int32_t", 'newmacro': "wchar_t"})
     419        else:
     420                macros.append({'oldmacro': "__WCHAR_TYPE__", 'newmacro': "wchar_t"})
     421       
     422        fnd = True
     423       
     424        if (not 'wint' in probe['builtins']):
     425                print_warning(['The compiler does not provide the macro __WINT_TYPE__',
     426                               'for defining the compiler-native type wint_t. We are',
     427                               'forced to define wint_t as a hardwired type int32_t.',
     428                               COMPILER_WARNING])
     429                fnd = False
     430       
     431        if (probe['builtins']['wint']['value'] != 4):
     432                print_warning(['The compiler provided macro __WINT_TYPE__ for defining',
     433                               'the compiler-native type wint_t is not compliant with',
     434                               'HelenOS. We are forced to define wint_t as a hardwired',
     435                               'type int32_t.',
     436                               COMPILER_WARNING])
     437                fnd = False
     438       
     439        if (not fnd):
     440                macros.append({'oldmacro': "int32_t", 'newmacro': "wint_t"})
     441        else:
     442                macros.append({'oldmacro': "__WINT_TYPE__", 'newmacro': "wint_t"})
    339443       
    340444        return {'macros': macros, 'typedefs': typedefs}
     
    508612                probe = probe_compiler(common,
    509613                        [
    510                                 {'type': 'char', 'tag': 'CHAR'},
    511                                 {'type': 'short int', 'tag': 'SHORT'},
    512                                 {'type': 'int', 'tag': 'INT'},
    513                                 {'type': 'long int', 'tag': 'LONG'},
    514                                 {'type': 'long long int', 'tag': 'LLONG'}
     614                                {'type': 'long long int', 'tag': 'LLONG', 'strc': '"ll"', 'conc': '"LL"'},
     615                                {'type': 'long int', 'tag': 'LONG', 'strc': '"l"', 'conc': '"L"'},
     616                                {'type': 'int', 'tag': 'INT', 'strc': '""', 'conc': '""'},
     617                                {'type': 'short int', 'tag': 'SHORT', 'strc': '"h"', 'conc': '"@"'},
     618                                {'type': 'char', 'tag': 'CHAR', 'strc': '"hh"', 'conc': '"@@"'}
    515619                        ]
    516620                )
    517621               
    518                 maps = detect_uints(probe, [1, 2, 4, 8])
     622                maps = detect_uints(probe, [1, 2, 4, 8], ['CHAR', 'SHORT', 'INT', 'LONG', 'LLONG'])
    519623               
    520624        finally:
  • tools/config.py

    r8e58f94 r7bdcc45  
    33# Copyright (c) 2006 Ondrej Palkovsky
    44# Copyright (c) 2009 Martin Decky
     5# Copyright (c) 2010 Jiri Svoboda
    56# All rights reserved.
    67#
     
    4041import xtui
    4142
    42 INPUT = sys.argv[1]
     43RULES_FILE = sys.argv[1]
    4344MAKEFILE = 'Makefile.config'
    4445MACROS = 'config.h'
    45 PRECONF = 'defaults'
    46 
    47 def read_defaults(fname, defaults):
    48         "Read saved values from last configuration run"
     46PRESETS_DIR = 'defaults'
     47
     48def read_config(fname, config):
     49        "Read saved values from last configuration run or a preset file"
    4950       
    5051        inf = open(fname, 'r')
     
    5253        for line in inf:
    5354                res = re.match(r'^(?:#!# )?([^#]\w*)\s*=\s*(.*?)\s*$', line)
    54                 if (res):
    55                         defaults[res.group(1)] = res.group(2)
     55                if res:
     56                        config[res.group(1)] = res.group(2)
    5657       
    5758        inf.close()
    5859
    59 def check_condition(text, defaults, ask_names):
     60def check_condition(text, config, rules):
    6061        "Check that the condition specified on input line is True (only CNF and DNF is supported)"
    6162       
    6263        ctype = 'cnf'
    6364       
    64         if ((')|' in text) or ('|(' in text)):
     65        if (')|' in text) or ('|(' in text):
    6566                ctype = 'dnf'
    6667       
    67         if (ctype == 'cnf'):
     68        if ctype == 'cnf':
    6869                conds = text.split('&')
    6970        else:
     
    7172       
    7273        for cond in conds:
    73                 if (cond.startswith('(')) and (cond.endswith(')')):
     74                if cond.startswith('(') and cond.endswith(')'):
    7475                        cond = cond[1:-1]
    7576               
    76                 inside = check_inside(cond, defaults, ctype)
     77                inside = check_inside(cond, config, ctype)
    7778               
    7879                if (ctype == 'cnf') and (not inside):
    7980                        return False
    8081               
    81                 if (ctype == 'dnf') and (inside):
     82                if (ctype == 'dnf') and inside:
    8283                        return True
    8384       
    84         if (ctype == 'cnf'):
     85        if ctype == 'cnf':
    8586                return True
    8687        return False
    8788
    88 def check_inside(text, defaults, ctype):
     89def check_inside(text, config, ctype):
    8990        "Check for condition"
    9091       
    91         if (ctype == 'cnf'):
     92        if ctype == 'cnf':
    9293                conds = text.split('|')
    9394        else:
     
    9697        for cond in conds:
    9798                res = re.match(r'^(.*?)(!?=)(.*)$', cond)
    98                 if (not res):
     99                if not res:
    99100                        raise RuntimeError("Invalid condition: %s" % cond)
    100101               
     
    103104                condval = res.group(3)
    104105               
    105                 if (not condname in defaults):
     106                if not condname in config:
    106107                        varval = ''
    107108                else:
    108                         varval = defaults[condname]
     109                        varval = config[condname]
    109110                        if (varval == '*'):
    110111                                varval = 'y'
    111112               
    112                 if (ctype == 'cnf'):
     113                if ctype == 'cnf':
    113114                        if (oper == '=') and (condval == varval):
    114115                                return True
     
    123124                                return False
    124125       
    125         if (ctype == 'cnf'):
     126        if ctype == 'cnf':
    126127                return False
    127128       
    128129        return True
    129130
    130 def parse_config(fname, ask_names):
    131         "Parse configuration file"
     131def parse_rules(fname, rules):
     132        "Parse rules file"
    132133       
    133134        inf = open(fname, 'r')
     
    138139        for line in inf:
    139140               
    140                 if (line.startswith('!')):
     141                if line.startswith('!'):
    141142                        # Ask a question
    142143                        res = re.search(r'!\s*(?:\[(.*?)\])?\s*([^\s]+)\s*\((.*)\)\s*$', line)
    143144                       
    144                         if (not res):
     145                        if not res:
    145146                                raise RuntimeError("Weird line: %s" % line)
    146147                       
     
    149150                        vartype = res.group(3)
    150151                       
    151                         ask_names.append((varname, vartype, name, choices, cond))
     152                        rules.append((varname, vartype, name, choices, cond))
    152153                        name = ''
    153154                        choices = []
    154155                        continue
    155156               
    156                 if (line.startswith('@')):
     157                if line.startswith('@'):
    157158                        # Add new line into the 'choices' array
    158159                        res = re.match(r'@\s*(?:\[(.*?)\])?\s*"(.*?)"\s*(.*)$', line)
     
    164165                        continue
    165166               
    166                 if (line.startswith('%')):
     167                if line.startswith('%'):
    167168                        # Name of the option
    168169                        name = line[1:].strip()
    169170                        continue
    170171               
    171                 if ((line.startswith('#')) or (line == '\n')):
     172                if line.startswith('#') or (line == '\n'):
    172173                        # Comment or empty line
    173174                        continue
     
    181182        "Return '*' if yes, ' ' if no"
    182183       
    183         if (default == 'y'):
     184        if default == 'y':
    184185                return '*'
    185186       
     
    199200        cnt = 0
    200201        for key, val in choices:
    201                 if ((default) and (key == default)):
     202                if (default) and (key == default):
    202203                        position = cnt
    203204               
     
    207208        (button, value) = xtui.choice_window(screen, name, 'Choose value', options, position)
    208209       
    209         if (button == 'cancel'):
     210        if button == 'cancel':
    210211                return None
    211212       
    212213        return choices[value][0]
    213214
    214 def check_choices(defaults, ask_names):
    215         "Check whether all accessible variables have a default"
    216        
    217         for varname, vartype, name, choices, cond in ask_names:
    218                 if ((cond) and (not check_condition(cond, defaults, ask_names))):
     215## Infer and verify configuration values.
     216#
     217# Augment @a config with values that can be inferred, purge invalid ones
     218# and verify that all variables have a value (previously specified or inferred).
     219#
     220# @param config Configuration to work on
     221# @param rules  Rules
     222#
     223# @return True if configuration is complete and valid, False
     224#         otherwise.
     225#
     226def infer_verify_choices(config, rules):
     227        "Infer and verify configuration values."
     228       
     229        for rule in rules:
     230                varname, vartype, name, choices, cond = rule
     231               
     232                if cond and (not check_condition(cond, config, rules)):
    219233                        continue
    220234               
    221                 if (not varname in defaults):
     235                if not varname in config:
     236                        value = None
     237                else:
     238                        value = config[varname]
     239               
     240                if not validate_rule_value(rule, value):
     241                        value = None
     242               
     243                default = get_default_rule(rule)
     244
     245                #
     246                # If we don't have a value but we do have
     247                # a default, use it.
     248                #
     249                if value == None and default != None:
     250                        value = default
     251                        config[varname] = default
     252               
     253                if not varname in config:
    222254                        return False
    223255       
    224256        return True
    225257
    226 def create_output(mkname, mcname, defaults, ask_names):
     258## Get default value from a rule.
     259def get_default_rule(rule):
     260        varname, vartype, name, choices, cond = rule
     261       
     262        default = None
     263       
     264        if vartype == 'choice':
     265                # If there is just one option, use it
     266                if len(choices) == 1:
     267                        default = choices[0][0]
     268        elif vartype == 'y':
     269                default = '*'
     270        elif vartype == 'n':
     271                default = 'n'
     272        elif vartype == 'y/n':
     273                default = 'y'
     274        elif vartype == 'n/y':
     275                default = 'n'
     276        else:
     277                raise RuntimeError("Unknown variable type: %s" % vartype)
     278       
     279        return default
     280
     281## Get option from a rule.
     282#
     283# @param rule  Rule for a variable
     284# @param value Current value of the variable
     285#
     286# @return Option (string) to ask or None which means not to ask.
     287#
     288def get_rule_option(rule, value):
     289        varname, vartype, name, choices, cond = rule
     290       
     291        option = None
     292       
     293        if vartype == 'choice':
     294                # If there is just one option, don't ask
     295                if len(choices) != 1:
     296                        if (value == None):
     297                                option = "?     %s --> " % name
     298                        else:
     299                                option = "      %s [%s] --> " % (name, value)
     300        elif vartype == 'y':
     301                pass
     302        elif vartype == 'n':
     303                pass
     304        elif vartype == 'y/n':
     305                option = "  <%s> %s " % (yes_no(value), name)
     306        elif vartype == 'n/y':
     307                option ="  <%s> %s " % (yes_no(value), name)
     308        else:
     309                raise RuntimeError("Unknown variable type: %s" % vartype)
     310       
     311        return option
     312
     313## Check if variable value is valid.
     314#
     315# @param rule  Rule for the variable
     316# @param value Value of the variable
     317#
     318# @return True if valid, False if not valid.
     319#
     320def validate_rule_value(rule, value):
     321        varname, vartype, name, choices, cond = rule
     322       
     323        if value == None:
     324                return True
     325       
     326        if vartype == 'choice':
     327                if not value in [choice[0] for choice in choices]:
     328                        return False
     329        elif vartype == 'y':
     330                if value != 'y':
     331                        return False
     332        elif vartype == 'n':
     333                if value != 'n':
     334                        return False
     335        elif vartype == 'y/n':
     336                if not value in ['y', 'n']:
     337                        return False
     338        elif vartype == 'n/y':
     339                if not value in ['y', 'n']:
     340                        return False
     341        else:
     342                raise RuntimeError("Unknown variable type: %s" % vartype)
     343       
     344        return True
     345
     346def create_output(mkname, mcname, config, rules):
    227347        "Create output configuration"
    228348       
     
    238358                sys.stderr.write("failed\n")
    239359       
    240         if (len(version) == 3):
     360        if len(version) == 3:
    241361                revision = version[1]
    242                 if (version[0] != 1):
     362                if version[0] != 1:
    243363                        revision += 'M'
    244364                revision += ' (%s)' % version[2]
     
    259379        defs = 'CONFIG_DEFS ='
    260380       
    261         for varname, vartype, name, choices, cond in ask_names:
    262                 if ((cond) and (not check_condition(cond, defaults, ask_names))):
     381        for varname, vartype, name, choices, cond in rules:
     382                if cond and (not check_condition(cond, config, rules)):
    263383                        continue
    264384               
    265                 if (not varname in defaults):
    266                         default = ''
     385                if not varname in config:
     386                        value = ''
    267387                else:
    268                         default = defaults[varname]
    269                         if (default == '*'):
    270                                 default = 'y'
    271                
    272                 outmk.write('# %s\n%s = %s\n\n' % (name, varname, default))
    273                
    274                 if ((vartype == "y") or (vartype == "n") or (vartype == "y/n") or (vartype == "n/y")):
    275                         if (default == "y"):
     388                        value = config[varname]
     389                        if (value == '*'):
     390                                value = 'y'
     391               
     392                outmk.write('# %s\n%s = %s\n\n' % (name, varname, value))
     393               
     394                if vartype in ["y", "n", "y/n", "n/y"]:
     395                        if value == "y":
    276396                                outmc.write('/* %s */\n#define %s\n\n' % (name, varname))
    277397                                defs += ' -D%s' % varname
    278398                else:
    279                         outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, default, varname, default))
    280                         defs += ' -D%s=%s -D%s_%s' % (varname, default, varname, default)
    281        
    282         if (revision is not None):
     399                        outmc.write('/* %s */\n#define %s %s\n#define %s_%s\n\n' % (name, varname, value, varname, value))
     400                        defs += ' -D%s=%s -D%s_%s' % (varname, value, varname, value)
     401       
     402        if revision is not None:
    283403                outmk.write('REVISION = %s\n' % revision)
    284404                outmc.write('#define REVISION %s\n' % revision)
     
    299419        return list
    300420
    301 def read_preconfigured(root, fname, screen, defaults):
     421## Ask user to choose a configuration profile.
     422#
     423def choose_profile(root, fname, screen, config):
    302424        options = []
    303425        opt2path = {}
     
    309431                canon = os.path.join(path, fname)
    310432               
    311                 if ((os.path.isdir(path)) and (os.path.exists(canon)) and (os.path.isfile(canon))):
     433                if os.path.isdir(path) and os.path.exists(canon) and os.path.isfile(canon):
    312434                        subprofile = False
    313435                       
     
    317439                                subcanon = os.path.join(subpath, fname)
    318440                               
    319                                 if ((os.path.isdir(subpath)) and (os.path.exists(subcanon)) and (os.path.isfile(subcanon))):
     441                                if os.path.isdir(subpath) and os.path.exists(subcanon) and os.path.isfile(subcanon):
    320442                                        subprofile = True
    321443                                        options.append("%s (%s)" % (name, subname))
    322                                         opt2path[cnt] = (canon, subcanon)
     444                                        opt2path[cnt] = [name, subname]
    323445                                        cnt += 1
    324446                       
    325                         if (not subprofile):
     447                        if not subprofile:
    326448                                options.append(name)
    327                                 opt2path[cnt] = (canon, None)
     449                                opt2path[cnt] = [name]
    328450                                cnt += 1
    329451       
    330452        (button, value) = xtui.choice_window(screen, 'Load preconfigured defaults', 'Choose configuration profile', options, None)
    331453       
    332         if (button == 'cancel'):
     454        if button == 'cancel':
    333455                return None
    334456       
    335         read_defaults(opt2path[value][0], defaults)
    336         if (opt2path[value][1] != None):
    337                 read_defaults(opt2path[value][1], defaults)
     457        return opt2path[value]
     458
     459## Read presets from a configuration profile.
     460#
     461# @param profile Profile to load from (a list of string components)
     462# @param config  Output configuration
     463#
     464def read_presets(profile, config):
     465        path = os.path.join(PRESETS_DIR, profile[0], MAKEFILE)
     466        read_config(path, config)
     467       
     468        if len(profile) > 1:
     469                path = os.path.join(PRESETS_DIR, profile[0], profile[1], MAKEFILE)
     470                read_config(path, config)
     471
     472## Parse profile name (relative OS path) into a list of components.
     473#
     474# @param profile_name Relative path (using OS separator)
     475# @return             List of components
     476#
     477def parse_profile_name(profile_name):
     478        profile = []
     479       
     480        head, tail = os.path.split(profile_name)
     481        if head != '':
     482                profile.append(head)
     483       
     484        profile.append(tail)
     485        return profile
    338486
    339487def main():
    340         defaults = {}
    341         ask_names = []
    342        
    343         # Parse configuration file
    344         parse_config(INPUT, ask_names)
    345        
    346         # Read defaults from previous run
    347         if os.path.exists(MAKEFILE):
    348                 read_defaults(MAKEFILE, defaults)
    349        
    350         # Default mode: only check defaults and regenerate configuration
    351         if ((len(sys.argv) >= 3) and (sys.argv[2] == 'default')):
    352                 if (check_choices(defaults, ask_names)):
    353                         create_output(MAKEFILE, MACROS, defaults, ask_names)
     488        profile = None
     489        config = {}
     490        rules = []
     491       
     492        # Parse rules file
     493        parse_rules(RULES_FILE, rules)
     494       
     495        # Input configuration file can be specified on command line
     496        # otherwise configuration from previous run is used.
     497        if len(sys.argv) >= 4:
     498                profile = parse_profile_name(sys.argv[3])
     499                read_presets(profile, config)
     500        elif os.path.exists(MAKEFILE):
     501                read_config(MAKEFILE, config)
     502       
     503        # Default mode: check values and regenerate configuration files
     504        if (len(sys.argv) >= 3) and (sys.argv[2] == 'default'):
     505                if (infer_verify_choices(config, rules)):
     506                        create_output(MAKEFILE, MACROS, config, rules)
    354507                        return 0
    355508       
    356         # Check mode: only check defaults
    357         if ((len(sys.argv) >= 3) and (sys.argv[2] == 'check')):
    358                 if (check_choices(defaults, ask_names)):
     509        # Hands-off mode: check values and regenerate configuration files,
     510        # but no interactive fallback
     511        if (len(sys.argv) >= 3) and (sys.argv[2] == 'hands-off'):
     512                # We deliberately test sys.argv >= 4 because we do not want
     513                # to read implicitly any possible previous run configuration
     514                if len(sys.argv) < 4:
     515                        sys.stderr.write("Configuration error: No presets specified\n")
     516                        return 2
     517               
     518                if (infer_verify_choices(config, rules)):
     519                        create_output(MAKEFILE, MACROS, config, rules)
     520                        return 0
     521               
     522                sys.stderr.write("Configuration error: The presets are ambiguous\n")
     523                return 1
     524       
     525        # Check mode: only check configuration
     526        if (len(sys.argv) >= 3) and (sys.argv[2] == 'check'):
     527                if infer_verify_choices(config, rules):
    359528                        return 0
    360529                return 1
     
    366535                while True:
    367536                       
    368                         # Cancel out all defaults which have to be deduced
    369                         for varname, vartype, name, choices, cond in ask_names:
    370                                 if ((vartype == 'y') and (varname in defaults) and (defaults[varname] == '*')):
    371                                         defaults[varname] = None
     537                        # Cancel out all values which have to be deduced
     538                        for varname, vartype, name, choices, cond in rules:
     539                                if (vartype == 'y') and (varname in config) and (config[varname] == '*'):
     540                                        config[varname] = None
    372541                       
    373542                        options = []
     
    377546                        options.append("  --- Load preconfigured defaults ... ")
    378547                       
    379                         for varname, vartype, name, choices, cond in ask_names:
    380                                
    381                                 if ((cond) and (not check_condition(cond, defaults, ask_names))):
     548                        for rule in rules:
     549                                varname, vartype, name, choices, cond = rule
     550                               
     551                                if cond and (not check_condition(cond, config, rules)):
    382552                                        continue
    383553                               
    384                                 if (varname == selname):
     554                                if varname == selname:
    385555                                        position = cnt
    386556                               
    387                                 if (not varname in defaults):
    388                                         default = None
     557                                if not varname in config:
     558                                        value = None
    389559                                else:
    390                                         default = defaults[varname]
    391                                
    392                                 if (vartype == 'choice'):
    393                                         # Check if the default is an acceptable value
    394                                         if ((default) and (not default in [choice[0] for choice in choices])):
    395                                                 default = None
    396                                                 defaults.pop(varname)
    397                                        
    398                                         # If there is just one option, use it
    399                                         if (len(choices) == 1):
    400                                                 defaults[varname] = choices[0][0]
    401                                                 continue
    402                                        
    403                                         if (default == None):
    404                                                 options.append("?     %s --> " % name)
    405                                         else:
    406                                                 options.append("      %s [%s] --> " % (name, default))
    407                                 elif (vartype == 'y'):
    408                                         defaults[varname] = '*'
     560                                        value = config[varname]
     561                               
     562                                if not validate_rule_value(rule, value):
     563                                        value = None
     564                               
     565                                default = get_default_rule(rule)
     566
     567                                #
     568                                # If we don't have a value but we do have
     569                                # a default, use it.
     570                                #
     571                                if value == None and default != None:
     572                                        value = default
     573                                        config[varname] = default
     574                               
     575                                option = get_rule_option(rule, value)
     576                                if option != None:
     577                                        options.append(option)
     578                                else:
    409579                                        continue
    410                                 elif (vartype == 'n'):
    411                                         defaults[varname] = 'n'
    412                                         continue
    413                                 elif (vartype == 'y/n'):
    414                                         if (default == None):
    415                                                 default = 'y'
    416                                                 defaults[varname] = default
    417                                         options.append("  <%s> %s " % (yes_no(default), name))
    418                                 elif (vartype == 'n/y'):
    419                                         if (default == None):
    420                                                 default = 'n'
    421                                                 defaults[varname] = default
    422                                         options.append("  <%s> %s " % (yes_no(default), name))
    423                                 else:
    424                                         raise RuntimeError("Unknown variable type: %s" % vartype)
    425580                               
    426581                                opt2row[cnt] = (varname, vartype, name, choices)
     
    433588                        (button, value) = xtui.choice_window(screen, 'HelenOS configuration', 'Choose configuration option', options, position)
    434589                       
    435                         if (button == 'cancel'):
     590                        if button == 'cancel':
    436591                                return 'Configuration canceled'
    437592                       
    438                         if (button == 'done'):
    439                                 if (check_choices(defaults, ask_names)):
     593                        if button == 'done':
     594                                if (infer_verify_choices(config, rules)):
    440595                                        break
    441596                                else:
     
    443598                                        continue
    444599                       
    445                         if (value == 0):
    446                                 read_preconfigured(PRECONF, MAKEFILE, screen, defaults)
     600                        if value == 0:
     601                                profile = choose_profile(PRESETS_DIR, MAKEFILE, screen, config)
     602                                if profile != None:
     603                                        read_presets(profile, config)
    447604                                position = 1
    448605                                continue
    449606                       
    450607                        position = None
    451                         if (not value in opt2row):
     608                        if not value in opt2row:
    452609                                raise RuntimeError("Error selecting value: %s" % value)
    453610                       
    454611                        (selname, seltype, name, choices) = opt2row[value]
    455612                       
    456                         if (not selname in defaults):
    457                                         default = None
     613                        if not selname in config:
     614                                value = None
    458615                        else:
    459                                 default = defaults[selname]
    460                        
    461                         if (seltype == 'choice'):
    462                                 defaults[selname] = subchoice(screen, name, choices, default)
    463                         elif ((seltype == 'y/n') or (seltype == 'n/y')):
    464                                 if (defaults[selname] == 'y'):
    465                                         defaults[selname] = 'n'
     616                                value = config[selname]
     617                       
     618                        if seltype == 'choice':
     619                                config[selname] = subchoice(screen, name, choices, value)
     620                        elif (seltype == 'y/n') or (seltype == 'n/y'):
     621                                if config[selname] == 'y':
     622                                        config[selname] = 'n'
    466623                                else:
    467                                         defaults[selname] = 'y'
     624                                        config[selname] = 'y'
    468625        finally:
    469626                xtui.screen_done(screen)
    470627       
    471         create_output(MAKEFILE, MACROS, defaults, ask_names)
     628        create_output(MAKEFILE, MACROS, config, rules)
    472629        return 0
    473630
Note: See TracChangeset for help on using the changeset viewer.