ra.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. # -*- coding: utf-8; mode: Python -*-
  2. # (c) Daniel Llorens - 2016, 2017-2023
  3. # This library is free software; you can redistribute it and/or modify it under
  4. # the terms of the GNU Lesser General Public License as published by the Free
  5. # Software Foundation; either version 3 of the License, or (at your option) any
  6. # later version.
  7. # Utilities for SConstructs
  8. import os, string
  9. # These are colorama names, but the dependence is a bother.
  10. class Fore: RED = '\x1b[31m'; YELLOW ='\x1b[33m'; RESET = '\x1b[39m'
  11. class Style: BRIGHT = '\x1b[1m'; RESET_ALL = '\x1b[0m';
  12. from os.path import join, abspath, split
  13. from subprocess import call
  14. # Make sure to disable (-fno-sanitize=all) for benchmarks.
  15. # SANITIZE = []
  16. SANITIZE = ['-fsanitize=address,leak,undefined']
  17. CXXFLAGS = ['-std=c++2b', '-Wall', '-Werror', '-Wlogical-op',
  18. '-fdiagnostics-color=always', '-Wno-unknown-pragmas',
  19. '-Wno-error=strict-overflow', '-Werror=zero-as-null-pointer-constant',
  20. #'-Wconversion',
  21. # '-funsafe-math-optimizations', # TODO Test with this.
  22. ] + SANITIZE
  23. LINKFLAGS = SANITIZE
  24. def blas_flags(Configure, env, arch):
  25. env_blas = env.Clone()
  26. if arch.find('apple-darwin') >= 0:
  27. # after OS X 10.14 giving -framework Accelerate isn't enough.
  28. # cf https://github.com/shogun-toolbox/shogun/commit/6db834fb4ca9783b6e5adfde808d60ebfca0abc9
  29. # cf https://github.com/BVLC/caffe/blob/master/cmake/Modules/FindvecLib.cmake
  30. cblas_possible_paths = ['/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/Headers/']
  31. for ppath in cblas_possible_paths:
  32. env0 = env.Clone()
  33. env0.Append(CPPPATH = [ppath])
  34. conf = Configure(env0)
  35. success = conf.CheckCHeader('cblas.h')
  36. conf.Finish()
  37. if success:
  38. print("cblas.h found at %r" % ppath)
  39. env_blas.Append(LINKFLAGS=' -framework Accelerate ')
  40. env_blas.Append(CPPPATH=[ppath])
  41. break
  42. else:
  43. print("cblas.h couldn't be found. Crossing fingers.")
  44. env_blas.Append(LINKFLAGS=' -framework Accelerate ')
  45. env_blas.Append(CCFLAGS=' -framework Accelerate ')
  46. else:
  47. env_blas.Append(LIBS=['blas'])
  48. return env_blas
  49. def ensure_ext(s, ext):
  50. "if s doesn't end with ext, append it."
  51. p = s.rfind(ext)
  52. return s if p+len(ext) == len(s) else s + ext
  53. def remove_ext(s):
  54. "clip string from the last dot until the end."
  55. p = s.rfind('.')
  56. assert p>=0, 'source must have an extension'
  57. return s[0:p]
  58. def path_parts(path):
  59. path, tail = split(path)
  60. return ([path] if path == os.sep else path_parts(path) if path else []) \
  61. + ([tail] if tail else [])
  62. def take_from_environ(env, var, wrapper=(lambda x: x), default=None):
  63. if var in os.environ and os.environ[var]!='':
  64. env[var] = wrapper(os.environ[var])
  65. elif default is not None:
  66. env[var] = default
  67. def get_value_wo_error(dictionary, key, default = ''):
  68. if key in dictionary:
  69. return dictionary[key]
  70. else:
  71. return default
  72. def dict_index_list(dictionary, list_of_keys):
  73. return dict([ (k, get_value_wo_error(dictionary, k))
  74. for k in list_of_keys ])
  75. def to_test(env, variant_dir, source, args):
  76. """
  77. Run program with args to produce a check stamp. The name of the first source
  78. is used to generate the name of the stamp.
  79. """
  80. class tester:
  81. def __init__(self, args):
  82. self.args = args
  83. def __call__(self, target, source, env):
  84. print("-> running %s \n___________________" % str(self.args))
  85. r = os.spawnl(os.P_WAIT, self.args[0], self.args[0], *self.args[1:])
  86. print("^^^^^^^^^^^^^^^^^^^")
  87. print('r ', r)
  88. if not r:
  89. print("PASSED %s" % str(self.args))
  90. call(['touch', target[0].abspath])
  91. else:
  92. print("FAILED %s" % str(self.args))
  93. return r
  94. stamp = env.File(join(variant_dir, str(source[0])) + "".join(args[1:]) + '.test')
  95. return env.Command(stamp, source, tester(args))
  96. # def to_source(env, targets, source):
  97. # main = source[0]
  98. # for target in targets: env.Notangle(target, remove_ext(main)+'.nw')
  99. # env.Noweave(remove_ext(main)+'.tex', remove_ext(main)+'.nw')
  100. # env.PDF(remove_ext(main), remove_ext(main)+'.tex')
  101. def to_source_from_noweb(env, targets, source):
  102. main = source[0]
  103. env.Noweave(remove_ext(main) + '.tex', remove_ext(main) + '.nw')
  104. env.PDF(remove_ext(main), remove_ext(main) + '.tex')
  105. return [env.Notangle(target, remove_ext(main) + '.nw') for target in targets]
  106. def to_test_ra(env_, variant_dir):
  107. def f(source, target='', cxxflags=[], cppdefines=[]):
  108. if len(cxxflags)==0 or len(cppdefines)==0:
  109. env = env_
  110. else:
  111. env = env_.Clone()
  112. env.Append(CXXFLAGS=cxxflags + ['-U' + k for k in cppdefines.keys()], CPPDEFINES=cppdefines)
  113. if len(target)==0:
  114. target = source
  115. obj = env.Object(target, [source + '.cc'])
  116. test = env.Program(target, obj)
  117. to_test(env, variant_dir, test, [test[0].abspath])
  118. return f
  119. def print_summary(GetBuildFailures, tag):
  120. test_item_tally = 0
  121. test_tally = 0
  122. build_tally = 0
  123. print('\n' + Style.BRIGHT + 'Summary for ' + tag + Style.RESET_ALL + '\n--------')
  124. for bf in GetBuildFailures():
  125. if str(bf.node).endswith('.test') and (bf.status > 0):
  126. print((Style.BRIGHT + Fore.RED + '%s ' + Style.RESET_ALL + Fore.RESET + ' failed (%d)') \
  127. % (bf.node, bf.status))
  128. test_item_tally += bf.status
  129. test_tally += 1
  130. else:
  131. print((Style.BRIGHT + Fore.YELLOW + '%s ' + Style.RESET_ALL + Fore.RESET + ' failed (%s)') \
  132. % (bf.node, bf.errstr))
  133. build_tally += 1
  134. print('%d targets failed to build.' % build_tally)
  135. print('%d tests failed with %d total failures.' % (test_tally, test_item_tally))