summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2024-12-09 12:06:47 +0100
committerDylan Baker <dylan@pnwbakers.com>2024-12-10 13:29:58 -0800
commit8156e12ce0de62aa47472e529489f7412628e6e5 (patch)
treeead204c8cac2657a6ceee92ce26646f6a99ed081
parent54cab0910e26e82f5d4cd7c087781ed7826d649a (diff)
downloadmeson-8156e12ce0de62aa47472e529489f7412628e6e5.tar.gz
separate mesondefine and cmakedefine logic
-rw-r--r--mesonbuild/utils/universal.py170
1 files changed, 125 insertions, 45 deletions
diff --git a/mesonbuild/utils/universal.py b/mesonbuild/utils/universal.py
index 88d8e1f89..76a6df8da 100644
--- a/mesonbuild/utils/universal.py
+++ b/mesonbuild/utils/universal.py
@@ -1173,6 +1173,46 @@ def join_args(args: T.Iterable[str]) -> str:
def do_replacement(regex: T.Pattern[str], line: str,
variable_format: Literal['meson', 'cmake', 'cmake@'],
confdata: T.Union[T.Dict[str, T.Tuple[str, T.Optional[str]]], 'ConfigurationData']) -> T.Tuple[str, T.Set[str]]:
+ if variable_format == 'meson':
+ return do_replacement_meson(regex, line, confdata)
+ elif variable_format in {'cmake', 'cmake@'}:
+ return do_replacement_cmake(regex, line, variable_format == 'cmake@', confdata)
+ else:
+ raise MesonException('Invalid variable format')
+
+def do_replacement_meson(regex: T.Pattern[str], line: str,
+ confdata: T.Union[T.Dict[str, T.Tuple[str, T.Optional[str]]], 'ConfigurationData']) -> T.Tuple[str, T.Set[str]]:
+ missing_variables: T.Set[str] = set()
+
+ def variable_replace(match: T.Match[str]) -> str:
+ # Pairs of escape characters before '@', '\@', '${' or '\${'
+ if match.group(0).endswith('\\'):
+ num_escapes = match.end(0) - match.start(0)
+ return '\\' * (num_escapes // 2)
+ # \@escaped\@ variables
+ elif match.groupdict().get('escaped') is not None:
+ return match.group('escaped')[1:-2]+'@'
+ else:
+ # Template variable to be replaced
+ varname = match.group('variable')
+ var_str = ''
+ if varname in confdata:
+ var, _ = confdata.get(varname)
+ if isinstance(var, str):
+ var_str = var
+ elif isinstance(var, int):
+ var_str = str(var)
+ else:
+ msg = f'Tried to replace variable {varname!r} value with ' \
+ f'something other than a string or int: {var!r}'
+ raise MesonException(msg)
+ else:
+ missing_variables.add(varname)
+ return var_str
+ return re.sub(regex, variable_replace, line), missing_variables
+
+def do_replacement_cmake(regex: T.Pattern[str], line: str, at_only: bool,
+ confdata: T.Union[T.Dict[str, T.Tuple[str, T.Optional[str]]], 'ConfigurationData']) -> T.Tuple[str, T.Set[str]]:
missing_variables: T.Set[str] = set()
def variable_replace(match: T.Match[str]) -> str:
@@ -1181,7 +1221,7 @@ def do_replacement(regex: T.Pattern[str], line: str,
num_escapes = match.end(0) - match.start(0)
return '\\' * (num_escapes // 2)
# Handle cmake escaped \${} tags
- elif variable_format == 'cmake' and match.group(0) == '\\${':
+ elif not at_only and match.group(0) == '\\${':
return '${'
# \@escaped\@ variables
elif match.groupdict().get('escaped') is not None:
@@ -1194,7 +1234,7 @@ def do_replacement(regex: T.Pattern[str], line: str,
var, _ = confdata.get(varname)
if isinstance(var, str):
var_str = var
- elif variable_format.startswith("cmake") and isinstance(var, bool):
+ elif isinstance(var, bool):
var_str = str(int(var))
elif isinstance(var, int):
var_str = str(var)
@@ -1207,11 +1247,36 @@ def do_replacement(regex: T.Pattern[str], line: str,
return var_str
return re.sub(regex, variable_replace, line), missing_variables
-def do_define(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData',
- variable_format: Literal['meson', 'cmake', 'cmake@'], subproject: T.Optional[SubProject] = None) -> str:
- cmake_bool_define = False
- if variable_format != "meson":
- cmake_bool_define = "cmakedefine01" in line
+def do_define_meson(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData',
+ subproject: T.Optional[SubProject] = None) -> str:
+
+ arr = line.split()
+ if len(arr) != 2:
+ raise MesonException('#mesondefine does not contain exactly two tokens: %s' % line.strip())
+
+ varname = arr[1]
+ try:
+ v, _ = confdata.get(varname)
+ except KeyError:
+ return '/* #undef %s */\n' % varname
+
+ if isinstance(v, str):
+ result = f'#define {varname} {v}'.strip() + '\n'
+ result, _ = do_replacement_meson(regex, result, confdata)
+ return result
+ elif isinstance(v, bool):
+ if v:
+ return '#define %s\n' % varname
+ else:
+ return '#undef %s\n' % varname
+ elif isinstance(v, int):
+ return '#define %s %d\n' % (varname, v)
+ else:
+ raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)
+
+def do_define_cmake(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData', at_only: bool,
+ subproject: T.Optional[SubProject] = None) -> str:
+ cmake_bool_define = 'cmakedefine01' in line
def get_cmake_define(line: str, confdata: 'ConfigurationData') -> str:
arr = line.split()
@@ -1230,12 +1295,10 @@ def do_define(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData',
return ' '.join(define_value)
arr = line.split()
- if len(arr) != 2:
- if variable_format == 'meson':
- raise MesonException('#mesondefine does not contain exactly two tokens: %s' % line.strip())
- elif subproject is not None:
- from ..interpreterbase.decorators import FeatureNew
- FeatureNew.single_use('cmakedefine without exactly two tokens', '0.54.1', subproject)
+
+ if len(arr) != 2 and subproject is not None:
+ from ..interpreterbase.decorators import FeatureNew
+ FeatureNew.single_use('cmakedefine without exactly two tokens', '0.54.1', subproject)
varname = arr[1]
try:
@@ -1246,26 +1309,13 @@ def do_define(regex: T.Pattern[str], line: str, confdata: 'ConfigurationData',
else:
return '/* #undef %s */\n' % varname
- if isinstance(v, str) or variable_format != "meson":
- if variable_format == 'meson':
- result = v
- else:
- if not cmake_bool_define and not v:
- return '/* #undef %s */\n' % varname
+ if not cmake_bool_define and not v:
+ return '/* #undef %s */\n' % varname
- result = get_cmake_define(line, confdata)
- result = f'#define {varname} {result}'.strip() + '\n'
- result, _ = do_replacement(regex, result, variable_format, confdata)
- return result
- elif isinstance(v, bool):
- if v:
- return '#define %s\n' % varname
- else:
- return '#undef %s\n' % varname
- elif isinstance(v, int):
- return '#define %s %d\n' % (varname, v)
- else:
- raise MesonException('#mesondefine argument "%s" is of unknown type.' % varname)
+ result = get_cmake_define(line, confdata)
+ result = f'#define {varname} {result}'.strip() + '\n'
+ result, _ = do_replacement_cmake(regex, result, at_only, confdata)
+ return result
def get_variable_regex(variable_format: Literal['meson', 'cmake', 'cmake@'] = 'meson') -> T.Pattern[str]:
# Only allow (a-z, A-Z, 0-9, _, -) as valid characters for a define
@@ -1291,20 +1341,50 @@ def get_variable_regex(variable_format: Literal['meson', 'cmake', 'cmake@'] = 'm
def do_conf_str(src: str, data: T.List[str], confdata: 'ConfigurationData',
variable_format: Literal['meson', 'cmake', 'cmake@'],
subproject: T.Optional[SubProject] = None) -> T.Tuple[T.List[str], T.Set[str], bool]:
- def line_is_valid(line: str, variable_format: str) -> bool:
- if variable_format == 'meson':
+ if variable_format == 'meson':
+ return do_conf_str_meson(src, data, confdata, subproject)
+ elif variable_format in {'cmake', 'cmake@'}:
+ return do_conf_str_cmake(src, data, confdata, variable_format == 'cmake@', subproject)
+ else:
+ raise MesonException('Invalid variable format')
+
+def do_conf_str_meson(src: str, data: T.List[str], confdata: 'ConfigurationData',
+ subproject: T.Optional[SubProject] = None) -> T.Tuple[T.List[str], T.Set[str], bool]:
+
+ regex = get_variable_regex('meson')
+
+ search_token = '#mesondefine'
+
+ result: T.List[str] = []
+ missing_variables: T.Set[str] = set()
+ # Detect when the configuration data is empty and no tokens were found
+ # during substitution so we can warn the user to use the `copy:` kwarg.
+ confdata_useless = not confdata.keys()
+ for line in data:
+ if line.lstrip().startswith(search_token):
+ confdata_useless = False
+ line = do_define_meson(regex, line, confdata, subproject)
+ else:
if '#cmakedefine' in line:
- return False
- else: # cmake format
- if '#mesondefine' in line:
- return False
- return True
+ raise MesonException(f'Format error in {src}: saw "{line.strip()}" when format set to "meson"')
+ line, missing = do_replacement_meson(regex, line, confdata)
+ missing_variables.update(missing)
+ if missing:
+ confdata_useless = False
+ result.append(line)
+
+ return result, missing_variables, confdata_useless
+
+def do_conf_str_cmake(src: str, data: T.List[str], confdata: 'ConfigurationData', at_only: bool,
+ subproject: T.Optional[SubProject] = None) -> T.Tuple[T.List[str], T.Set[str], bool]:
+
+ variable_format: Literal['cmake', 'cmake@'] = 'cmake'
+ if at_only:
+ variable_format = 'cmake@'
regex = get_variable_regex(variable_format)
- search_token = '#mesondefine'
- if variable_format != 'meson':
- search_token = '#cmakedefine'
+ search_token = '#cmakedefine'
result: T.List[str] = []
missing_variables: T.Set[str] = set()
@@ -1314,11 +1394,11 @@ def do_conf_str(src: str, data: T.List[str], confdata: 'ConfigurationData',
for line in data:
if line.lstrip().startswith(search_token):
confdata_useless = False
- line = do_define(regex, line, confdata, variable_format, subproject)
+ line = do_define_cmake(regex, line, confdata, at_only, subproject)
else:
- if not line_is_valid(line, variable_format):
+ if '#mesondefine' in line:
raise MesonException(f'Format error in {src}: saw "{line.strip()}" when format set to "{variable_format}"')
- line, missing = do_replacement(regex, line, variable_format, confdata)
+ line, missing = do_replacement_cmake(regex, line, at_only, confdata)
missing_variables.update(missing)
if missing:
confdata_useless = False