aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mintro.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/mintro.py')
-rw-r--r--mesonbuild/mintro.py144
1 files changed, 41 insertions, 103 deletions
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index 2039553..36368af 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -151,20 +151,20 @@ def list_targets(builddata: build.Build, installdata, backend: backends.Backend)
tlist.append(t)
return tlist
-class BuildoptionsOptionHelper:
+class IntrospectionHelper:
# mimic an argparse namespace
def __init__(self, cross_file):
self.cross_file = cross_file
self.native_file = None
self.cmd_line_options = {}
-class BuildoptionsInterperter(astinterpreter.AstInterpreter):
+class IntrospectionInterpreter(astinterpreter.AstInterpreter):
# Interpreter to detect the options without a build directory
# Most of the code is stolen from interperter.Interpreter
def __init__(self, source_root, subdir, backend, cross_file=None, subproject='', subproject_dir='subprojects', env=None):
super().__init__(source_root, subdir)
- options = BuildoptionsOptionHelper(cross_file)
+ options = IntrospectionHelper(cross_file)
self.cross_file = cross_file
if env is None:
self.environment = environment.Environment(source_root, None, options)
@@ -176,37 +176,18 @@ class BuildoptionsInterperter(astinterpreter.AstInterpreter):
self.option_file = os.path.join(self.source_root, self.subdir, 'meson_options.txt')
self.backend = backend
self.default_options = {'backend': self.backend}
+ self.project_data = {}
self.funcs.update({
'project': self.func_project,
'add_languages': self.func_add_languages
})
- def detect_compilers(self, lang, need_cross_compiler):
- comp, cross_comp = self.environment.detect_compilers(lang, need_cross_compiler)
- if comp is None:
- return None, None
-
- self.coredata.compilers[lang] = comp
- # Native compiler always exist so always add its options.
- new_options = comp.get_options()
- if cross_comp is not None:
- self.coredata.cross_compilers[lang] = cross_comp
- new_options.update(cross_comp.get_options())
-
- optprefix = lang + '_'
- for k, o in new_options.items():
- if not k.startswith(optprefix):
- raise RuntimeError('Internal error, %s has incorrect prefix.' % k)
- if k in self.environment.cmd_line_options:
- o.set_value(self.environment.cmd_line_options[k])
- self.coredata.compiler_options.setdefault(k, o)
-
- return comp, cross_comp
-
def flatten_args(self, args):
# Resolve mparser.ArrayNode if needed
flattend_args = []
+ if isinstance(args, mparser.ArrayNode):
+ args = [x.value for x in args.args.arguments]
for i in args:
if isinstance(i, mparser.ArrayNode):
flattend_args += [x.value for x in i.args.arguments]
@@ -216,35 +197,25 @@ class BuildoptionsInterperter(astinterpreter.AstInterpreter):
pass
return flattend_args
- def add_languages(self, args):
- need_cross_compiler = self.environment.is_cross_build()
- for lang in sorted(args, key=compilers.sort_clink):
- lang = lang.lower()
- if lang not in self.coredata.compilers:
- (comp, _) = self.detect_compilers(lang, need_cross_compiler)
- if comp is None:
- return
- for optname in comp.base_options:
- if optname in self.coredata.base_options:
- continue
- oobj = compilers.base_options[optname]
- self.coredata.base_options[optname] = oobj
-
def func_project(self, node, args, kwargs):
if len(args) < 1:
raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.')
+ proj_name = args[0]
+ proj_vers = kwargs.get('version', 'undefined')
proj_langs = self.flatten_args(args[1:])
+ if isinstance(proj_vers, mparser.ElementaryNode):
+ proj_vers = proj_vers.value
+ if not isinstance(proj_vers, str):
+ proj_vers = 'undefined'
+ self.project_data = {'descriptive_name': proj_name, 'version': proj_vers}
if os.path.exists(self.option_file):
oi = optinterpreter.OptionInterpreter(self.subproject)
oi.process(self.option_file)
self.coredata.merge_user_options(oi.options)
- def_opts = kwargs.get('default_options', [])
- if isinstance(def_opts, mparser.ArrayNode):
- def_opts = [x.value for x in def_opts.args.arguments]
-
+ def_opts = self.flatten_args(kwargs.get('default_options', []))
self.project_default_options = mesonlib.stringlistify(def_opts)
self.project_default_options = cdata.create_options_dict(self.project_default_options)
self.default_options.update(self.project_default_options)
@@ -255,6 +226,7 @@ class BuildoptionsInterperter(astinterpreter.AstInterpreter):
if isinstance(spdirname, str):
self.subproject_dir = spdirname
if not self.is_subproject():
+ self.project_data['subprojects'] = []
subprojects_dir = os.path.join(self.source_root, self.subproject_dir)
if os.path.isdir(subprojects_dir):
for i in os.listdir(subprojects_dir):
@@ -265,19 +237,26 @@ class BuildoptionsInterperter(astinterpreter.AstInterpreter):
options = {k: v for k, v in self.environment.cmd_line_options.items() if k.startswith('backend_')}
self.coredata.set_options(options)
- self.add_languages(proj_langs)
+ self.func_add_languages(None, proj_langs, None)
def do_subproject(self, dirname):
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
subpr = os.path.join(subproject_dir_abs, dirname)
try:
- subi = BuildoptionsInterperter(subpr, '', self.backend, cross_file=self.cross_file, subproject=dirname, subproject_dir=self.subproject_dir, env=self.environment)
+ subi = IntrospectionInterpreter(subpr, '', self.backend, cross_file=self.cross_file, subproject=dirname, subproject_dir=self.subproject_dir, env=self.environment)
subi.analyze()
+ subi.project_data['name'] = dirname
+ self.project_data['subprojects'] += [subi.project_data]
except:
return
def func_add_languages(self, node, args, kwargs):
- return self.add_languages(self.flatten_args(args))
+ args = self.flatten_args(args)
+ need_cross_compiler = self.environment.is_cross_build()
+ for lang in sorted(args, key=compilers.sort_clink):
+ lang = lang.lower()
+ if lang not in self.coredata.compilers:
+ self.environment.detect_compilers(lang, need_cross_compiler)
def is_subproject(self):
return self.subproject != ''
@@ -292,7 +271,7 @@ def list_buildoptions_from_source(sourcedir, backend, indent):
# Make sure that log entries in other parts of meson don't interfere with the JSON output
mlog.disable()
backend = backends.get_backend_from_name(backend, None)
- intr = BuildoptionsInterperter(sourcedir, '', backend.name)
+ intr = IntrospectionInterpreter(sourcedir, '', backend.name)
intr.analyze()
# Reenable logging just in case
mlog.enable()
@@ -438,60 +417,22 @@ def list_projinfo(builddata: build.Build):
result['subprojects'] = subprojects
return result
-class ProjectInfoInterperter(astinterpreter.AstInterpreter):
- def __init__(self, source_root, subdir):
- super().__init__(source_root, subdir)
- self.funcs.update({'project': self.func_project})
- self.project_name = None
- self.project_version = None
-
- def func_project(self, node, args, kwargs):
- if len(args) < 1:
- raise InvalidArguments('Not enough arguments to project(). Needs at least the project name.')
- self.project_name = args[0]
- self.project_version = kwargs.get('version', 'undefined')
- if isinstance(self.project_version, mparser.ElementaryNode):
- self.project_version = self.project_version.value
-
- def set_variable(self, varname, variable):
- pass
-
- def analyze(self):
- self.load_root_meson_file()
- self.sanity_check_ast()
- self.parse_project()
- self.run()
-
def list_projinfo_from_source(sourcedir, indent):
files = find_buildsystem_files_list(sourcedir)
+ files = [os.path.normpath(x) for x in files]
- result = {'buildsystem_files': []}
- subprojects = {}
-
- for f in files:
- f = f.replace('\\', '/')
- if f == 'meson.build':
- interpreter = ProjectInfoInterperter(sourcedir, '')
- interpreter.analyze()
- version = None
- if interpreter.project_version is str:
- version = interpreter.project_version
- result.update({'version': version, 'descriptive_name': interpreter.project_name})
- result['buildsystem_files'].append(f)
- elif f.startswith('subprojects/'):
- subproject_id = f.split('/')[1]
- subproject = subprojects.setdefault(subproject_id, {'buildsystem_files': []})
- subproject['buildsystem_files'].append(f)
- if f.count('/') == 2 and f.endswith('meson.build'):
- interpreter = ProjectInfoInterperter(os.path.join(sourcedir, 'subprojects', subproject_id), '')
- interpreter.analyze()
- subproject.update({'name': subproject_id, 'version': interpreter.project_version, 'descriptive_name': interpreter.project_name})
- else:
- result['buildsystem_files'].append(f)
+ mlog.disable()
+ intr = IntrospectionInterpreter(sourcedir, '', 'ninja')
+ intr.analyze()
+ mlog.enable()
- subprojects = [obj for name, obj in subprojects.items()]
- result['subprojects'] = subprojects
- print(json.dumps(result, indent=indent))
+ for i in intr.project_data['subprojects']:
+ basedir = os.path.join(intr.subproject_dir, i['name'])
+ i['buildsystem_files'] = [x for x in files if x.startswith(basedir)]
+ files = [x for x in files if not x.startswith(basedir)]
+
+ intr.project_data['buildsystem_files'] = files
+ print(json.dumps(intr.project_data, indent=indent))
def run(options):
datadir = 'meson-private'
@@ -532,13 +473,8 @@ def run(options):
return 1
results = []
- toextract = []
intro_types = get_meson_introspection_types()
- for i in intro_types.keys():
- if options.all or getattr(options, i, False):
- toextract += [i]
-
# Handle the one option that does not have its own JSON file (meybe deprecate / remove this?)
if options.target_files is not None:
targets_file = os.path.join(infodir, 'intro-targets.json')
@@ -547,7 +483,9 @@ def run(options):
results += [('target_files', list_target_files(options.target_files, targets, source_dir))]
# Extract introspection information from JSON
- for i in toextract:
+ for i in intro_types.keys():
+ if not options.all and not getattr(options, i, False):
+ continue
curr = os.path.join(infodir, 'intro-{}.json'.format(i))
if not os.path.isfile(curr):
print('Introspection file {} does not exist.'.format(curr))