1import logging 2import os 3import re 4import subprocess 5 6import dune.common.module 7 8from dune.common.utility import buffer_to_str 9from dune.generator import builder, ConfigurationError 10 11logger = logging.getLogger(__name__) 12 13def assertHave(identifier): 14 '''check if an identifier is defined equal to 1 in the dune-py config.h file. 15 use this to check if for example #define HAVE_DUNE_COMMON 1 is 16 provided the config file by calling 17 assertHave("HAVE_DUNE_COMMON") 18 ''' 19 config = os.path.join(dune.common.module.get_dune_py_dir(), "config.h") 20 21 matches = [match for match in [re.match('^[ ]*#define[ ]+' + identifier.strip() + '[ ]+1$', line) for line in open(config)] if match is not None] 22 if not matches: 23 matches = [match for match in [re.match('^[ ]*#define[ ]+' + identifier.strip() + '[ ]+ENABLE', line) for line in open(config)] if match is not None] 24 25 if not matches: 26 raise ConfigurationError(identifier + " is not set in dune-py's config.h") 27 elif matches.__len__() > 1: 28 raise ConfigurationError(identifier + " found multiple times in dune-py's config.h") 29 30def assertCMakeVariable(identifier,value,defaultFails): 31 '''check if a variable in CMakeCache.txt in dune-py is defined and equal to 'value' 32 ''' 33 cache = os.path.join(dune.common.module.get_dune_py_dir(), "CMakeCache.txt") 34 35 identifier = identifier.lower().strip() 36 matches = [line.lower() for line in open(cache) if re.match('^[ ]*'+identifier+':+', line.lower()) is not None] 37 if not matches and defaultFails: 38 raise ConfigurationError(identifier + " default behavior is used in dune-py and that is not allowed") 39 elif len(matches) > 1: 40 raise ConfigurationError(identifier + " found multiple times in dune-py's config.h") 41 elif matches: 42 # check for bool on/off type variables: 43 bools = {True:["on","true","1"], False:["off","false","0"]} 44 if not [x for x in bools[value] if x in matches[0]]: 45 raise ConfigurationError(identifier + " dune-py wrongly configured wrt "+identifier) 46 47def preprocessorAssert(tests): 48 '''perform preprocessore checks. 49 A list of checks can be provided each should contain a pair, the 50 first being the preprocessor check to perform (e.g. #if or #ifdef) 51 and the second being the message to print if the check fails. The 52 generated code is of the form: 53 tests[i][0] 54 #else 55 test failed 56 #endif 57 so the first argument of each test has to make this piece of code 58 valid C++ code assuming config.h is included. 59 ''' 60 source = "#include <config.h>\nint main() {\n" 61 i = 0 62 for t in tests: 63 source = source + t[0]+"\n#else\nreturn "+str(i+1)+";\n#endif\n" 64 i += 1 65 source = source + "return 0;\n}\n" 66 67 with open(os.path.join(builder.generated_dir, "generated_module.hh"), 'w') as out: 68 out.write(source) 69 builder.compile("generated_test") 70 71 test_args = ["./generated_test"] 72 test = subprocess.Popen(test_args, cwd=builder.generated_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 73 stdout, stderr = test.communicate() 74 logger.debug(buffer_to_str(stdout)) 75 returncode = test.returncode 76 77 if returncode > 0: 78 logger.debug("failed testing:\n"+source) 79 logger.critical("checking "+tests[returncode-1][0]+" failed: "+tests[returncode-1][1]) 80 raise ConfigurationError(tests[returncode-1][1]) 81