SCons.Conftest

Package SCons :: Module Conftest |
[hide private]
[frames] | no frames]

# Source Code for Module SCons.Conftest

      1  """SCons.Conftest
      2
      3  Autoconf-like configuration support; low level implementation of tests.
      4  """
      5
      6  #
      7  # Copyright (c) 2003 Stichting NLnet Labs
      8  # Copyright (c) 2001, 2002, 2003 Steven Knight
      9  #
     10  # Permission is hereby granted, free of charge, to any person obtaining
     11  # a copy of this software and associated documentation files (the
     12  # "Software"), to deal in the Software without restriction, including
     13  # without limitation the rights to use, copy, modify, merge, publish,
     14  # distribute, sublicense, and/or sell copies of the Software, and to
     15  # permit persons to whom the Software is furnished to do so, subject to
     16  # the following conditions:
     17  #
     18  # The above copyright notice and this permission notice shall be included
     19  # in all copies or substantial portions of the Software.
     20  #
     21  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
     22  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
     23  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     24  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     25  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     26  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     27  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     28  #
     29
     30  #
     31  # The purpose of this module is to define how a check is to be performed.
     32  # Use one of the Check...() functions below.
     33  #
     34
     35  #
     36  # A context class is used that defines functions for carrying out the tests,
     37  # logging and messages.  The following methods and members must be present:
     38  #
     39  # context.Display(msg)  Function called to print messages that are normally
     40  #                       displayed for the user.  Newlines are explicitly used.
     41  #                       The text should also be written to the logfile!
     42  #
     43  # context.Log(msg)      Function called to write to a log file.
     44  #
     45  # context.BuildProg(text, ext)
     46  #                       Function called to build a program, using "ext" for the
     47  #                       file extention.  Must return an empty string for
     48  #                       success, an error message for failure.
     49  #                       For reliable test results building should be done just
     50  #                       like an actual program would be build, using the same
     51  #                       command and arguments (including configure results so
     52  #                       far).
     53  #
     54  # context.CompileProg(text, ext)
     55  #                       Function called to compile a program, using "ext" for
     56  #                       the file extention.  Must return an empty string for
     57  #                       success, an error message for failure.
     58  #                       For reliable test results compiling should be done just
     59  #                       like an actual source file would be compiled, using the
     60  #                       same command and arguments (including configure results
     61  #                       so far).
     62  #
     63  # context.AppendLIBS(lib_name_list)
     64  #                       Append "lib_name_list" to the value of LIBS.
     65  #                       "lib_namelist" is a list of strings.
     66  #                       Return the value of LIBS before changing it (any type
     67  #                       can be used, it is passed to SetLIBS() later.
     68  #
     69  # context.SetLIBS(value)
     70  #                       Set LIBS to "value".  The type of "value" is what
     71  #                       AppendLIBS() returned.
     72  #                       Return the value of LIBS before changing it (any type
     73  #                       can be used, it is passed to SetLIBS() later.
     74  #
     75  # context.headerfilename
     76  #                       Name of file to append configure results to, usually
     77  #                       "confdefs.h".
     78  #                       The file must not exist or be empty when starting.
     79  #                       Empty or None to skip this (some tests will not work!).
     80  #
     81  # context.config_h      (may be missing). If present, must be a string, which
     82  #                       will be filled with the contents of a config_h file.
     83  #
     84  # context.vardict       Dictionary holding variables used for the tests and
     85  #                       stores results from the tests, used for the build
     86  #                       commands.
     87  #                       Normally contains "CC", "LIBS", "CPPFLAGS", etc.
     88  #
     89  # context.havedict      Dictionary holding results from the tests that are to
     90  #                       be used inside a program.
     91  #                       Names often start with "HAVE_".  These are zero
     92  #                       (feature not present) or one (feature present).  Other
     93  #                       variables may have any value, e.g., "PERLVERSION" can
     94  #                       be a number and "SYSTEMNAME" a string.
     95  #
     96
     97  import re
     98  import string
     99  from types import IntType
    100
    101  #
    102  # PUBLIC VARIABLES
    103  #
    104
    105  LogInputFiles = 1    # Set that to log the input files in case of a failed test
    106  LogErrorMessages = 1 # Set that to log Conftest-generated error messages
    107
    108  #
    109  # PUBLIC FUNCTIONS
    110  #
    111
    112  # Generic remarks:
    113  # - When a language is specified which is not supported the test fails.  The
    114  #   message is a bit different, because not all the arguments for the normal
    115  #   message are available yet (chicken-egg problem).
    116
    117
    118 -def CheckBuilder(context, text = None, language = None):
    119      """
    120      Configure check to see if the compiler works.
    121      Note that this uses the current value of compiler and linker flags, make
    122      sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
    123      "language" should be "C" or "C++" and is used to select the compiler.
    124      Default is "C".
    125      "text" may be used to specify the code to be build.
    126      Returns an empty string for success, an error message for failure.
    127      """
    128      lang, suffix, msg = _lang2suffix(language)
    129      if msg:
    130          context.Display("%s\n" % msg)
    131          return msg
    132
    133      if not text:
    134          text = """
    135  int main() {
    136      return 0;
    137  }
    138  """
    139
    140      context.Display("Checking if building a %s file works... " % lang)
    141      ret = context.BuildProg(text, suffix)
    142      _YesNoResult(context, ret, None, text)
    143      return ret
    144
    145
    146 -def CheckFunc(context, function_name, header = None, language = None):
    147      """
    148      Configure check for a function "function_name".
    149      "language" should be "C" or "C++" and is used to select the compiler.
    150      Default is "C".
    151      Optional "header" can be defined to define a function prototype, include a
    152      header file or anything else that comes before main().
    153      Sets HAVE_function_name in context.havedict according to the result.
    154      Note that this uses the current value of compiler and linker flags, make
    155      sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
    156      Returns an empty string for success, an error message for failure.
    157      """
    158
    159      # Remarks from autoconf:
    160      # - Don't include <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>
    161      #   which includes <sys/select.h> which contains a prototype for select.
    162      #   Similarly for bzero.
    163      # - assert.h is included to define __stub macros and hopefully few
    164      #   prototypes, which can conflict with char $1(); below.
    165      # - Override any gcc2 internal prototype to avoid an error.
    166      # - We use char for the function declaration because int might match the
    167      #   return type of a gcc2 builtin and then its argument prototype would
    168      #   still apply.
    169      # - The GNU C library defines this for functions which it implements to
    170      #   always fail with ENOSYS.  Some functions are actually named something
    171      #   starting with __ and the normal name is an alias.
    172
    173      if context.headerfilename:
    174          includetext = '#include "%s"' % context.headerfilename
    175      else:
    176          includetext = ''
    177      if not header:
    178          header = """
    179  #ifdef __cplusplus
    180  extern "C"
    181  #endif
    182  char %s();""" % function_name
    183
    184      lang, suffix, msg = _lang2suffix(language)
    185      if msg:
    186          context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
    187          return msg
    188
    189      text = """
    190  %(include)s
    191  #include <assert.h>
    192  %(hdr)s
    193
    194  int main() {
    195  #if defined (__stub_%(name)s) || defined (__stub___%(name)s)
    196    fail fail fail
    197  #else
    198    %(name)s();
    199  #endif
    200
    201    return 0;
    202  }
    203  """ % { 'name': function_name,
    204          'include': includetext,
    205          'hdr': header }
    206
    207      context.Display("Checking for %s function %s()... " % (lang, function_name))
    208      ret = context.BuildProg(text, suffix)
    209      _YesNoResult(context, ret, "HAVE_" + function_name, text,
    210                   "Define to 1 if the system has the function `%s'." %\
    211                   function_name)
    212      return ret
    213
    214
    215 -def CheckHeader(context, header_name, header = None, language = None,
    216                                                          include_quotes = None):
    217      """
    218      Configure check for a C or C++ header file "header_name".
    219      Optional "header" can be defined to do something before including the
    220      header file (unusual, supported for consistency).
    221      "language" should be "C" or "C++" and is used to select the compiler.
    222      Default is "C".
    223      Sets HAVE_header_name in context.havedict according to the result.
    224      Note that this uses the current value of compiler and linker flags, make
    225      sure $CFLAGS and $CPPFLAGS are set correctly.
    226      Returns an empty string for success, an error message for failure.
    227      """
    228      # Why compile the program instead of just running the preprocessor?
    229      # It is possible that the header file exists, but actually using it may
    230      # fail (e.g., because it depends on other header files).  Thus this test is
    231      # more strict.  It may require using the "header" argument.
    232      #
    233      # Use <> by default, because the check is normally used for system header
    234      # files.  SCons passes '""' to overrule this.
    235
    236      # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
    237      if context.headerfilename:
    238          includetext = '#include "%s"\n' % context.headerfilename
    239      else:
    240          includetext = ''
    241      if not header:
    242          header = ""
    243
    244      lang, suffix, msg = _lang2suffix(language)
    245      if msg:
    246          context.Display("Cannot check for header file %s: %s\n"
    247                                                            % (header_name, msg))
    248          return msg
    249
    250      if not include_quotes:
    251          include_quotes = "<>"
    252
    253      text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
    254                               include_quotes[0], header_name, include_quotes[1])
    255
    256      context.Display("Checking for %s header file %s... " % (lang, header_name))
    257      ret = context.CompileProg(text, suffix)
    258      _YesNoResult(context, ret, "HAVE_" + header_name, text,
    259                   "Define to 1 if you have the <%s> header file." % header_name)
    260      return ret
    261
    262
    263 -def CheckType(context, type_name, fallback = None,
    264                                                 header = None, language = None):
    265      """
    266      Configure check for a C or C++ type "type_name".
    267      Optional "header" can be defined to include a header file.
    268      "language" should be "C" or "C++" and is used to select the compiler.
    269      Default is "C".
    270      Sets HAVE_type_name in context.havedict according to the result.
    271      Note that this uses the current value of compiler and linker flags, make
    272      sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
    273      Returns an empty string for success, an error message for failure.
    274      """
    275
    276      # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
    277      if context.headerfilename:
    278          includetext = '#include "%s"' % context.headerfilename
    279      else:
    280          includetext = ''
    281      if not header:
    282          header = ""
    283
    284      lang, suffix, msg = _lang2suffix(language)
    285      if msg:
    286          context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
    287          return msg
    288
    289      # Remarks from autoconf about this test:
    290      # - Grepping for the type in include files is not reliable (grep isn't
    291      #   portable anyway).
    292      # - Using "TYPE my_var;" doesn't work for const qualified types in C++.
    293      #   Adding an initializer is not valid for some C++ classes.
    294      # - Using the type as parameter to a function either fails for K&$ C or for
    295      #   C++.
    296      # - Using "TYPE *my_var;" is valid in C for some types that are not
    297      #   declared (struct something).
    298      # - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.
    299      # - Using the previous two together works reliably.
    300      text = """
    301  %(include)s
    302  %(header)s
    303
    304  int main() {
    305    if ((%(name)s *) 0)
    306      return 0;
    307    if (sizeof (%(name)s))
    308      return 0;
    309  }
    310  """ % { 'include': includetext,
    311          'header': header,
    312          'name': type_name }
    313
    314      context.Display("Checking for %s type %s... " % (lang, type_name))
    315      ret = context.BuildProg(text, suffix)
    316      _YesNoResult(context, ret, "HAVE_" + type_name, text,
    317                   "Define to 1 if the system has the type `%s'." % type_name)
    318      if ret and fallback and context.headerfilename:
    319          f = open(context.headerfilename, "a")
    320          f.write("typedef %s %s;\n" % (fallback, type_name))
    321          f.close()
    322
    323      return ret
    324
    325 -def CheckTypeSize(context, type_name, header = None, language = None, expect = None):
    326      """This check can be used to get the size of a given type, or to check whether
    327      the type is of expected size.
    328
    329      Arguments:
    330          - type : str
    331              the type to check
    332          - includes : sequence
    333              list of headers to include in the test code before testing the type
    334          - language : str
    335              'C' or 'C++'
    336          - expect : int
    337              if given, will test wether the type has the given number of bytes.
    338              If not given, will automatically find the size.
    339
    340          Returns:
    341              status : int
    342                  0 if the check failed, or the found size of the type if the check succeeded."""
    343
    344      # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
    345      if context.headerfilename:
    346          includetext = '#include "%s"' % context.headerfilename
    347      else:
    348          includetext = ''
    349
    350      if not header:
    351          header = ""
    352
    353      lang, suffix, msg = _lang2suffix(language)
    354      if msg:
    355          context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
    356          return msg
    357
    358      src = includetext + header
    359      if not expect is None:
    360          # Only check if the given size is the right one
    361          context.Display('Checking %s is %d bytes... ' % (type_name, expect))
    362
    363          # test code taken from autoconf: this is a pretty clever hack to find that
    364          # a type is of a given size using only compilation. This speeds things up
    365          # quite a bit compared to straightforward code using TryRun
    366          src = src + r"""
    367  typedef %s scons_check_type;
    368
    369  int main()
    370  {
    371      static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
    372      test_array[0] = 0;
    373
    374      return 0;
    375  }
    376  """
    377
    378          st = context.CompileProg(src % (type_name, expect), suffix)
    379          if not st:
    380              context.Display("yes\n")
    381              _Have(context, "SIZEOF_%s" % type_name, expect,
    382                    "The size of `%s', as computed by sizeof." % type_name)
    383              return expect
    384          else:
    385              context.Display("no\n")
    386              _LogFailed(context, src, st)
    387              return 0
    388      else:
    389          # Only check if the given size is the right one
    390          context.Message('Checking size of %s ... ' % type_name)
    391
    392          # We have to be careful with the program we wish to test here since
    393          # compilation will be attempted using the current environment's flags.
    394          # So make sure that the program will compile without any warning. For
    395          # example using: 'int main(int argc, char** argv)' will fail with the
    396          # '-Wall -Werror' flags since the variables argc and argv would not be
    397          # used in the program...
    398          #
    399          src = src + """
    400  #include <stdlib.h>
    401  #include <stdio.h>
    402  int main() {
    403      printf("%d", (int)sizeof(""" + type_name + """));
    404      return 0;
    405  }
    406      """
    407          st, out = context.RunProg(src, suffix)
    408          try:
    409              size = int(out)
    410          except ValueError:
    411              # If cannot convert output of test prog to an integer (the size),
    412              # something went wront, so just fail
    413              st = 1
    414              size = 0
    415
    416          if not st:
    417              context.Display("yes\n")
    418              _Have(context, "SIZEOF_%s" % type_name, size,
    419                    "The size of `%s', as computed by sizeof." % type_name)
    420              return size
    421          else:
    422              context.Display("no\n")
    423              _LogFailed(context, src, st)
    424              return 0
    425
    426      return 0
    427
    428 -def CheckDeclaration(context, symbol, includes = None, language = None):
    429      """Checks whether symbol is declared.
    430
    431      Use the same test as autoconf, that is test whether the symbol is defined
    432      as a macro or can be used as an r-value.
    433
    434      Arguments:
    435          symbol : str
    436              the symbol to check
    437          includes : str
    438              Optional "header" can be defined to include a header file.
    439          language : str
    440              only C and C++ supported.
    441
    442      Returns:
    443          status : bool
    444              True if the check failed, False if succeeded."""
    445
    446      # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
    447      if context.headerfilename:
    448          includetext = '#include "%s"' % context.headerfilename
    449      else:
    450          includetext = ''
    451
    452      if not includes:
    453          includes = ""
    454
    455      lang, suffix, msg = _lang2suffix(language)
    456      if msg:
    457          context.Display("Cannot check for declaration %s: %s\n" % (type_name, msg))
    458          return msg
    459
    460      src = includetext + includes
    461      context.Display('Checking whether %s is declared... ' % symbol)
    462
    463      src = src + r"""
    464  int main()
    465  {
    466  #ifndef %s
    467      (void) %s;
    468  #endif
    469      ;
    470      return 0;
    471  }
    472  """ % (symbol, symbol)
    473
    474      st = context.CompileProg(src, suffix)
    475      _YesNoResult(context, st, "HAVE_DECL_" + symbol, src,
    476                   "Set to 1 if %s is defined." % symbol)
    477      return st
    478
    479 -def CheckLib(context, libs, func_name = None, header = None,
    480                   extra_libs = None, call = None, language = None, autoadd = 1):
    481      """
    482      Configure check for a C or C++ libraries "libs".  Searches through
    483      the list of libraries, until one is found where the test succeeds.
    484      Tests if "func_name" or "call" exists in the library.  Note: if it exists
    485      in another library the test succeeds anyway!
    486      Optional "header" can be defined to include a header file.  If not given a
    487      default prototype for "func_name" is added.
    488      Optional "extra_libs" is a list of library names to be added after
    489      "lib_name" in the build command.  To be used for libraries that "lib_name"
    490      depends on.
    491      Optional "call" replaces the call to "func_name" in the test code.  It must
    492      consist of complete C statements, including a trailing ";".
    493      Both "func_name" and "call" arguments are optional, and in that case, just
    494      linking against the libs is tested.
    495      "language" should be "C" or "C++" and is used to select the compiler.
    496      Default is "C".
    497      Note that this uses the current value of compiler and linker flags, make
    498      sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
    499      Returns an empty string for success, an error message for failure.
    500      """
    501      # Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
    502      if context.headerfilename:
    503          includetext = '#include "%s"' % context.headerfilename
    504      else:
    505          includetext = ''
    506      if not header:
    507          header = ""
    508
    509      text = """
    510  %s
    511  %s""" % (includetext, header)
    512
    513      # Add a function declaration if needed.
    514      if func_name and func_name != "main":
    515          if not header:
    516              text = text + """
    517  #ifdef __cplusplus
    518  extern "C"
    519  #endif
    520  char %s();
    521  """ % func_name
    522
    523          # The actual test code.
    524          if not call:
    525              call = "%s();" % func_name
    526
    527      # if no function to test, leave main() blank
    528      text = text + """
    529  int
    530  main() {
    531    %s
    532  return 0;
    533  }
    534  """ % (call or "")
    535
    536      if call:
    537          i = string.find(call, "\n")
    538          if i > 0:
    539              calltext = call[:i] + ".."
    540          elif call[-1] == ';':
    541              calltext = call[:-1]
    542          else:
    543              calltext = call
    544
    545      for lib_name in libs:
    546
    547          lang, suffix, msg = _lang2suffix(language)
    548          if msg:
    549              context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
    550              return msg
    551
    552          # if a function was specified to run in main(), say it
    553          if call:
    554                  context.Display("Checking for %s in %s library %s... "
    555                                  % (calltext, lang, lib_name))
    556          # otherwise, just say the name of library and language
    557          else:
    558                  context.Display("Checking for %s library %s... "
    559                                  % (lang, lib_name))
    560
    561          if lib_name:
    562              l = [ lib_name ]
    563              if extra_libs:
    564                  l.extend(extra_libs)
    565              oldLIBS = context.AppendLIBS(l)
    566              sym = "HAVE_LIB" + lib_name
    567          else:
    568              oldLIBS = -1
    569              sym = None
    570
    571          ret = context.BuildProg(text, suffix)
    572
    573          _YesNoResult(context, ret, sym, text,
    574                       "Define to 1 if you have the `%s' library." % lib_name)
    575          if oldLIBS != -1 and (ret or not autoadd):
    576              context.SetLIBS(oldLIBS)
    577
    578          if not ret:
    579              return ret
    580
    581      return ret
    582
    583  #
    584  # END OF PUBLIC FUNCTIONS
    585  #
    586
    587 -def _YesNoResult(context, ret, key, text, comment = None):
    588      """
    589      Handle the result of a test with a "yes" or "no" result.
    590      "ret" is the return value: empty if OK, error message when not.
    591      "key" is the name of the symbol to be defined (HAVE_foo).
    592      "text" is the source code of the program used for testing.
    593      "comment" is the C comment to add above the line defining the symbol (the
    594      comment is automatically put inside a /* */). If None, no comment is added.
    595      """
    596      if key:
    597          _Have(context, key, not ret, comment)
    598      if ret:
    599          context.Display("no\n")
    600          _LogFailed(context, text, ret)
    601      else:
    602          context.Display("yes\n")
    603
    604
    605 -def _Have(context, key, have, comment = None):
    606      """
    607      Store result of a test in context.havedict and context.headerfilename.
    608      "key" is a "HAVE_abc" name.  It is turned into all CAPITALS and non-
    609      alphanumerics are replaced by an underscore.
    610      The value of "have" can be:
    611      1      - Feature is defined, add "#define key".
    612      0      - Feature is not defined, add "/* #undef key */".
    613               Adding "undef" is what autoconf does.  Not useful for the
    614               compiler, but it shows that the test was done.
    615      number - Feature is defined to this number "#define key have".
    616               Doesn't work for 0 or 1, use a string then.
    617      string - Feature is defined to this string "#define key have".
    618               Give "have" as is should appear in the header file, include quotes
    619               when desired and escape special characters!
    620      """
    621      key_up = string.upper(key)
    622      key_up = re.sub('[^A-Z0-9_]', '_', key_up)
    623      context.havedict[key_up] = have
    624      if have == 1:
    625          line = "#define %s 1\n" % key_up
    626      elif have == 0:
    627          line = "/* #undef %s */\n" % key_up
    628      elif type(have) == IntType:
    629          line = "#define %s %d\n" % (key_up, have)
    630      else:
    631          line = "#define %s %s\n" % (key_up, str(have))
    632
    633      if comment is not None:
    634          lines = "\n/* %s */\n" % comment + line
    635      else:
    636          lines = "\n" + line
    637
    638      if context.headerfilename:
    639          f = open(context.headerfilename, "a")
    640          f.write(lines)
    641          f.close()
    642      elif hasattr(context,'config_h'):
    643          context.config_h = context.config_h + lines
    644
    645
    646 -def _LogFailed(context, text, msg):
    647      """
    648      Write to the log about a failed program.
    649      Add line numbers, so that error messages can be understood.
    650      """
    651      if LogInputFiles:
    652          context.Log("Failed program was:\n")
    653          lines = string.split(text, '\n')
    654          if len(lines) and lines[-1] == '':
    655              lines = lines[:-1]              # remove trailing empty line
    656          n = 1
    657          for line in lines:
    658              context.Log("%d: %s\n" % (n, line))
    659              n = n + 1
    660      if LogErrorMessages:
    661          context.Log("Error message: %s\n" % msg)
    662
    663
    664 -def _lang2suffix(lang):
    665      """
    666      Convert a language name to a suffix.
    667      When "lang" is empty or None C is assumed.
    668      Returns a tuple (lang, suffix, None) when it works.
    669      For an unrecognized language returns (None, None, msg).
    670      Where:
    671          lang   = the unified language name
    672          suffix = the suffix, including the leading dot
    673          msg    = an error message
    674      """
    675      if not lang or lang in ["C", "c"]:
    676          return ("C", ".c", None)
    677      if lang in ["c++", "C++", "cpp", "CXX", "cxx"]:
    678          return ("C++", ".cpp", None)
    679
    680      return None, None, "Unsupported language: %s" % lang
    681
    682
    683  # vim: set sw=4 et sts=4 tw=79 fo+=l:
    684