Skip to content

Commit

Permalink
Fix the use of get_option() as a parameter to project()
Browse files Browse the repository at this point in the history
  • Loading branch information
bcorby committed Dec 16, 2024
1 parent 0b41b36 commit 5eb9df3
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 18 deletions.
51 changes: 33 additions & 18 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from ..interpreterbase import noPosargs, noKwargs, permittedKwargs, noArgsFlattening, noSecondLevelHolderResolving, unholder_return
from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from ..interpreterbase import Disabler, disablerIfNotFound
from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureBroken, FeatureNewKwargs
from ..interpreterbase import FeatureNew, FeatureFixed, FeatureDeprecated, FeatureBroken, FeatureNewKwargs
from ..interpreterbase import ObjectHolder, ContextManagerObject
from ..interpreterbase import stringifyUserArguments
from ..modules import ExtensionModule, ModuleObject, MutableModuleObject, NewExtensionModule, NotFoundExtensionModule
Expand Down Expand Up @@ -1093,6 +1093,7 @@ def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str],
if optname_regex.search(optname.split('.', maxsplit=1)[-1]) is not None:
raise InterpreterException(f'Invalid option name {optname!r}')

self.load_options(nodes, args)
opt = self.get_option_internal(optname)
if isinstance(opt, options.UserFeatureOption):
opt.name = optname
Expand Down Expand Up @@ -1148,6 +1149,25 @@ def set_backend(self) -> None:
options = {k: v for k, v in self.environment.options.items() if self.environment.coredata.optstore.is_backend_option(k)}
self.coredata.set_options(options)

def load_options(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str]]) -> None:
# Read in the options file.
option_file = os.path.join(self.source_root, self.subdir, 'meson.options')
old_option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')
if not os.path.exists(option_file):
option_file = old_option_file
if os.path.exists(option_file):
with open(option_file, 'rb') as f:
# We want fast not cryptographically secure, this is just to
# see if the option file has changed
self.coredata.options_files[self.subproject] = (option_file, hashlib.sha1(f.read()).hexdigest())
oi = optinterpreter.OptionInterpreter(self.environment.coredata.optstore, self.subproject)
oi.process(option_file)
self.coredata.update_project_options(oi.options, self.subproject)
self.add_build_def_file(option_file)
else:
self.coredata.options_files[self.subproject] = None
self.load_options_used = True

@typed_pos_args('project', str, varargs=str)
@typed_kwargs(
'project',
Expand All @@ -1169,19 +1189,23 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str
if ':' in proj_name:
raise InvalidArguments(f"Project name {proj_name!r} must not contain ':'")

# If load_options() has already been called before we get here
# it must have been called from meson's get_option() function.
get_option_warning = hasattr(self, 'load_options_used')

# Read in the options file.
self.load_options(node, args)

# This needs to be evaluated as early as possible, as meson uses this
# for things like deprecation testing.
if kwargs['meson_version']:
self.handle_meson_version(kwargs['meson_version'], node)
else:
mesonlib.project_meson_versions[self.subproject] = mesonlib.NoProjectVersion()

# Load "meson.options" before "meson_options.txt", and produce a warning if
# it is being used with an old version. I have added check that if both
# exist the warning isn't raised
# Warn about use of meson.options / meson_options.txt.
option_file = os.path.join(self.source_root, self.subdir, 'meson.options')
old_option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')

if os.path.exists(option_file):
if os.path.exists(old_option_file):
if os.path.samefile(option_file, old_option_file):
Expand All @@ -1190,19 +1214,10 @@ def func_project(self, node: mparser.FunctionNode, args: T.Tuple[str, T.List[str
raise MesonException("meson.options and meson_options.txt both exist, but are not the same file.")
else:
FeatureNew.single_use('meson.options file', '1.1', self.subproject, 'Use meson_options.txt instead')
else:
option_file = old_option_file
if os.path.exists(option_file):
with open(option_file, 'rb') as f:
# We want fast not cryptographically secure, this is just to
# see if the option file has changed
self.coredata.options_files[self.subproject] = (option_file, hashlib.sha1(f.read()).hexdigest())
oi = optinterpreter.OptionInterpreter(self.environment.coredata.optstore, self.subproject)
oi.process(option_file)
self.coredata.update_project_options(oi.options, self.subproject)
self.add_build_def_file(option_file)
else:
self.coredata.options_files[self.subproject] = None

# Warn about using get_option() in project().
if get_option_warning:
FeatureFixed.single_use('Using get_option() function as a parameter to project()', '1.7', self.subproject)

if self.subproject:
self.project_default_options = {k.evolve(subproject=self.subproject): v
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/interpreterbase/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
'typed_kwargs',
'FeatureCheckBase',
'FeatureNew',
'FeatureFixed',
'FeatureDeprecated',
'FeatureBroken',
'FeatureNewKwargs',
'FeatureFixedKwargs',
'FeatureDeprecatedKwargs',

'InterpreterBase',
Expand Down Expand Up @@ -98,9 +100,11 @@
typed_kwargs,
FeatureCheckBase,
FeatureNew,
FeatureFixed,
FeatureDeprecated,
FeatureBroken,
FeatureNewKwargs,
FeatureFixedKwargs,
FeatureDeprecatedKwargs,
)

Expand Down
46 changes: 46 additions & 0 deletions mesonbuild/interpreterbase/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,49 @@ def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], locatio
args.append(self.extra_message)
mlog.warning(*args, location=location)

class FeatureFixed(FeatureCheckBase):
"""Checks for fixed features"""

# Class variable, shared across all instances
#
# Format: {subproject: {feature_version: set(feature_names)}}
feature_registry = {}

@staticmethod
def check_version(target_version: T.Union[str, mesonlib.NoProjectVersion], feature_version: str) -> bool:
if isinstance(target_version, str):
return mesonlib.version_compare_condition_with_min(target_version, feature_version)
else:
# Warn for anything newer than the current semver base slot.
major = coredata.version.split('.', maxsplit=1)[0]
return mesonlib.version_compare(feature_version, f'<{major}.0')

@staticmethod
def get_warning_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str:
if isinstance(tv, str):
return f'Project specifies a minimum meson_version \'{tv}\' but uses features which was fixed in newer versions:'
else:
return 'Project specifies no minimum version but uses features which was fixed in versions:'

@staticmethod
def get_notice_str_prefix(tv: T.Union[str, mesonlib.NoProjectVersion]) -> str:
return ''

def log_usage_warning(self, tv: T.Union[str, mesonlib.NoProjectVersion], location: T.Optional['mparser.BaseNode']) -> None:
if isinstance(tv, str):
prefix = f'Project targets {tv!r}'
else:
prefix = 'Project does not target a minimum version'
args = [
prefix,
'but uses feature fixed in',
f"'{self.feature_version}':",
f'{self.feature_name}.',
]
if self.extra_message:
args.append(self.extra_message)
mlog.warning(*args, location=location)

class FeatureDeprecated(FeatureCheckBase):
"""Checks for deprecated features"""

Expand Down Expand Up @@ -809,5 +852,8 @@ def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
class FeatureNewKwargs(FeatureCheckKwargsBase):
feature_check_class = FeatureNew

class FeatureFixedKwargs(FeatureCheckKwargsBase):
feature_check_class = FeatureFixed

class FeatureDeprecatedKwargs(FeatureCheckKwargsBase):
feature_check_class = FeatureDeprecated
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Project
project('test', 'c', version: '1.0' + get_option('append_to_version'))
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
option('append_to_version', type : 'string', value : '.0001', description : 'append to version')

0 comments on commit 5eb9df3

Please sign in to comment.