1import sys 2 3 4OS = sys.platform 5 6 7def _as_tuple(items): 8 if isinstance(items, str): 9 return tuple(items.strip().replace(',', ' ').split()) 10 elif items: 11 return tuple(items) 12 else: 13 return () 14 15 16class PreprocessorError(Exception): 17 """Something preprocessor-related went wrong.""" 18 19 @classmethod 20 def _msg(cls, filename, reason, **ignored): 21 msg = 'failure while preprocessing' 22 if reason: 23 msg = f'{msg} ({reason})' 24 return msg 25 26 def __init__(self, filename, preprocessor=None, reason=None): 27 if isinstance(reason, str): 28 reason = reason.strip() 29 30 self.filename = filename 31 self.preprocessor = preprocessor or None 32 self.reason = str(reason) if reason else None 33 34 msg = self._msg(**vars(self)) 35 msg = f'({filename}) {msg}' 36 if preprocessor: 37 msg = f'[{preprocessor}] {msg}' 38 super().__init__(msg) 39 40 41class PreprocessorFailure(PreprocessorError): 42 """The preprocessor command failed.""" 43 44 @classmethod 45 def _msg(cls, error, **ignored): 46 msg = 'preprocessor command failed' 47 if error: 48 msg = f'{msg} {error}' 49 return msg 50 51 def __init__(self, filename, argv, error=None, preprocessor=None): 52 exitcode = -1 53 if isinstance(error, tuple): 54 if len(error) == 2: 55 error, exitcode = error 56 else: 57 error = str(error) 58 if isinstance(error, str): 59 error = error.strip() 60 61 self.argv = _as_tuple(argv) or None 62 self.error = error if error else None 63 self.exitcode = exitcode 64 65 reason = str(self.error) 66 super().__init__(filename, preprocessor, reason) 67 68 69class ErrorDirectiveError(PreprocessorFailure): 70 """The file hit a #error directive.""" 71 72 @classmethod 73 def _msg(cls, error, **ignored): 74 return f'#error directive hit ({error})' 75 76 def __init__(self, filename, argv, error, *args, **kwargs): 77 super().__init__(filename, argv, error, *args, **kwargs) 78 79 80class MissingDependenciesError(PreprocessorFailure): 81 """The preprocessor did not have access to all the target's dependencies.""" 82 83 @classmethod 84 def _msg(cls, missing, **ignored): 85 msg = 'preprocessing failed due to missing dependencies' 86 if missing: 87 msg = f'{msg} ({", ".join(missing)})' 88 return msg 89 90 def __init__(self, filename, missing=None, *args, **kwargs): 91 self.missing = _as_tuple(missing) or None 92 93 super().__init__(filename, *args, **kwargs) 94 95 96class OSMismatchError(MissingDependenciesError): 97 """The target is not compatible with the host OS.""" 98 99 @classmethod 100 def _msg(cls, expected, **ignored): 101 return f'OS is {OS} but expected {expected or "???"}' 102 103 def __init__(self, filename, expected=None, *args, **kwargs): 104 if isinstance(expected, str): 105 expected = expected.strip() 106 107 self.actual = OS 108 self.expected = expected if expected else None 109 110 super().__init__(filename, None, *args, **kwargs) 111