aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/dependencies/base.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/dependencies/base.py')
-rw-r--r--mesonbuild/dependencies/base.py105
1 files changed, 71 insertions, 34 deletions
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index 1ccbf6f..21cd821 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -1546,13 +1546,27 @@ class CMakeDependency(ExternalDependency):
return True
return False
- def _cmake_set(self, tline: CMakeTraceLine):
+ def _cmake_set(self, tline: CMakeTraceLine) -> None:
+ """Handler for the CMake set() function in all variaties.
+
+ comes in three flavors:
+ set(<var> <value> [PARENT_SCOPE])
+ set(<var> <value> CACHE <type> <docstring> [FORCE])
+ set(ENV{<var>} <value>)
+
+ We don't support the ENV variant, and any uses of it will be ignored
+ silently. the other two variates are supported, with some caveats:
+ - we don't properly handle scoping, so calls to set() inside a
+ function without PARENT_SCOPE set could incorrectly shadow the
+ outer scope.
+ - We don't honor the type of CACHE arguments
+ """
# DOC: https://cmake.org/cmake/help/latest/command/set.html
# 1st remove PARENT_SCOPE and CACHE from args
args = []
for i in tline.args:
- if i == 'PARENT_SCOPE' or len(i) == 0:
+ if not i or i == 'PARENT_SCOPE':
continue
# Discard everything after the CACHE keyword
@@ -1564,13 +1578,19 @@ class CMakeDependency(ExternalDependency):
if len(args) < 1:
raise self._gen_exception('CMake: set() requires at least one argument\n{}'.format(tline))
- if len(args) == 1:
+ # Now that we've removed extra arguments all that should be left is the
+ # variable identifier and the value, join the value back together to
+ # ensure spaces in the value are correctly handled. This assumes that
+ # variable names don't have spaces. Please don't do that...
+ identifier = args.pop(0)
+ value = ' '.join(args)
+
+ if not value:
# Same as unset
- if args[0] in self.vars:
- del self.vars[args[0]]
+ if identifier in self.vars:
+ del self.vars[identifier]
else:
- values = list(itertools.chain(*map(lambda x: x.split(';'), args[1:])))
- self.vars[args[0]] = values
+ self.vars[identifier] = value.split(';')
def _cmake_unset(self, tline: CMakeTraceLine):
# DOC: https://cmake.org/cmake/help/latest/command/unset.html
@@ -1619,7 +1639,7 @@ class CMakeDependency(ExternalDependency):
self.targets[tline.args[0]] = CMakeTarget(tline.args[0], 'CUSTOM', {})
- def _cmake_set_property(self, tline: CMakeTraceLine):
+ def _cmake_set_property(self, tline: CMakeTraceLine) -> None:
# DOC: https://cmake.org/cmake/help/latest/command/set_property.html
args = list(tline.args)
@@ -1629,8 +1649,10 @@ class CMakeDependency(ExternalDependency):
append = False
targets = []
- while len(args) > 0:
+ while args:
curr = args.pop(0)
+ # XXX: APPEND_STRING is specifically *not* supposed to create a
+ # list, is treating them as aliases really okay?
if curr == 'APPEND' or curr == 'APPEND_STRING':
append = True
continue
@@ -1640,60 +1662,75 @@ class CMakeDependency(ExternalDependency):
targets.append(curr)
+ if not args:
+ raise self._gen_exception('CMake: set_property() faild to parse argument list\n{}'.format(tline))
+
if len(args) == 1:
# Tries to set property to nothing so nothing has to be done
return
- if len(args) < 2:
- raise self._gen_exception('CMake: set_property() faild to parse argument list\n{}'.format(tline))
-
- propName = args[0]
- propVal = list(itertools.chain(*map(lambda x: x.split(';'), args[1:])))
- propVal = list(filter(lambda x: len(x) > 0, propVal))
-
- if len(propVal) == 0:
+ identifier = args.pop(0)
+ value = ' '.join(args).split(';')
+ if not value:
return
for i in targets:
if i not in self.targets:
raise self._gen_exception('CMake: set_property() TARGET {} not found\n{}'.format(i, tline))
- if propName not in self.targets[i].properies:
- self.targets[i].properies[propName] = []
+ if identifier not in self.targets[i].properies:
+ self.targets[i].properies[identifier] = []
if append:
- self.targets[i].properies[propName] += propVal
+ self.targets[i].properies[identifier] += value
else:
- self.targets[i].properies[propName] = propVal
+ self.targets[i].properies[identifier] = value
- def _cmake_set_target_properties(self, tline: CMakeTraceLine):
+ def _cmake_set_target_properties(self, tline: CMakeTraceLine) -> None:
# DOC: https://cmake.org/cmake/help/latest/command/set_target_properties.html
args = list(tline.args)
targets = []
- while len(args) > 0:
+ while args:
curr = args.pop(0)
if curr == 'PROPERTIES':
break
targets.append(curr)
- if (len(args) % 2) != 0:
- raise self._gen_exception('CMake: set_target_properties() uneven number of property arguments\n{}'.format(tline))
-
- while len(args) > 0:
- propName = args.pop(0)
- propVal = args.pop(0).split(';')
- propVal = list(filter(lambda x: len(x) > 0, propVal))
-
- if len(propVal) == 0:
- continue
+ # Now we need to try to reconsitute the original quoted format of the
+ # arguments, as a property value could have spaces in it. Unlike
+ # set_property() this is not context free. There are two approaches I
+ # can think of, both have drawbacks:
+ #
+ # 1. Assume that the property will be capitalized, this is convention
+ # but cmake doesn't require it.
+ # 2. Maintain a copy of the list here: https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#target-properties
+ #
+ # Neither of these is awesome for obvious reasons. I'm going to try
+ # option 1 first and fall back to 2, as 1 requires less code and less
+ # synchroniztion for cmake changes.
+
+ arglist = [] # type: typing.List[typing.Tuple[str, typing.List[str]]]
+ name = args.pop(0)
+ values = []
+ for a in args:
+ if a.isupper():
+ if values:
+ arglist.append((name, ' '.join(values).split(';')))
+ name = a
+ values = []
+ else:
+ values.append(a)
+ if values:
+ arglist.append((name, ' '.join(values).split(';')))
+ for name, value in arglist:
for i in targets:
if i not in self.targets:
raise self._gen_exception('CMake: set_target_properties() TARGET {} not found\n{}'.format(i, tline))
- self.targets[i].properies[propName] = propVal
+ self.targets[i].properies[name] = value
def _lex_trace(self, trace):
# The trace format is: '<file>(<line>): <func>(<args -- can contain \n> )\n'