Skip to content

Commit 5eb5507

Browse files
bruchar1jpakkane
authored andcommitted
intro: add more details to generated json files
This will help with the writing of tools to generate VisualStudio project and solution files, and possibly for other IDEs as well. - Used compilers a about `host`, `build` and `target` machines arere listed in `intro-compilers.json` - Informations lister in `intro-machines.json` - `intro-dependencies.json` now includes internal dependencies, and relations between dependencies. - `intro-targets.json` now includes dependencies, `vs_module_defs`, `win_subsystem`, and linker parameters.
1 parent fbab148 commit 5eb5507

File tree

6 files changed

+172
-38
lines changed

6 files changed

+172
-38
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## More data in introspection files
2+
3+
- Used compilers are listed in `intro-compilers.json`
4+
- Informations about `host`, `build` and `target` machines
5+
are lister in `intro-machines.json`
6+
- `intro-dependencies.json` now includes internal dependencies,
7+
and relations between dependencies.
8+
- `intro-targets.json` now includes dependencies, `vs_module_defs`,
9+
`win_subsystem`, and linker parameters.

mesonbuild/backend/ninjabackend.py

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -746,7 +746,8 @@ def get_target_source_can_unity(self, target, source):
746746
return False
747747
return True
748748

749-
def create_target_source_introspection(self, target: build.Target, comp: compilers.Compiler, parameters, sources, generated_sources):
749+
def create_target_source_introspection(self, target: build.Target, comp: compilers.Compiler, parameters, sources, generated_sources,
750+
unity_sources: T.Optional[T.List[mesonlib.FileOrString]] = None):
750751
'''
751752
Adds the source file introspection information for a language of a target
752753
@@ -781,16 +782,40 @@ def create_target_source_introspection(self, target: build.Target, comp: compile
781782
'parameters': parameters,
782783
'sources': [],
783784
'generated_sources': [],
785+
'unity_sources': [],
784786
}
785787
tgt[id_hash] = src_block
786-
# Make source files absolute
787-
sources = [x.absolute_path(self.source_dir, self.build_dir) if isinstance(x, File) else os.path.normpath(os.path.join(self.build_dir, x))
788-
for x in sources]
789-
generated_sources = [x.absolute_path(self.source_dir, self.build_dir) if isinstance(x, File) else os.path.normpath(os.path.join(self.build_dir, x))
790-
for x in generated_sources]
791-
# Add the source files
792-
src_block['sources'] += sources
793-
src_block['generated_sources'] += generated_sources
788+
789+
def compute_path(file: mesonlib.FileOrString) -> str:
790+
""" Make source files absolute """
791+
if isinstance(file, File):
792+
return file.absolute_path(self.source_dir, self.build_dir)
793+
return os.path.normpath(os.path.join(self.build_dir, file))
794+
795+
src_block['sources'].extend(compute_path(x) for x in sources)
796+
src_block['generated_sources'].extend(compute_path(x) for x in generated_sources)
797+
if unity_sources:
798+
src_block['unity_sources'].extend(compute_path(x) for x in unity_sources)
799+
800+
def create_target_linker_introspection(self, target: build.Target, linker: T.Union[Compiler, StaticLinker], parameters):
801+
tid = target.get_id()
802+
tgt = self.introspection_data[tid]
803+
lnk_hash = tuple(parameters)
804+
lnk_block = tgt.get(lnk_hash, None)
805+
if lnk_block is None:
806+
if isinstance(parameters, CompilerArgs):
807+
parameters = parameters.to_native(copy=True)
808+
809+
if isinstance(linker, Compiler):
810+
linkers = linker.get_linker_exelist()
811+
else:
812+
linkers = linker.get_exelist()
813+
814+
lnk_block = {
815+
'linker': linkers,
816+
'parameters': parameters,
817+
}
818+
tgt[lnk_hash] = lnk_block
794819

795820
def generate_target(self, target):
796821
try:
@@ -985,7 +1010,7 @@ def generate_target(self, target):
9851010
if is_unity:
9861011
for src in self.generate_unity_files(target, unity_src):
9871012
o, s = self.generate_single_compile(target, src, True, unity_deps + header_deps + d_generated_deps,
988-
fortran_order_deps, fortran_inc_args)
1013+
fortran_order_deps, fortran_inc_args, unity_src)
9891014
obj_list.append(o)
9901015
compiled_sources.append(s)
9911016
source2object[s] = o
@@ -2809,7 +2834,8 @@ def _generate_single_compile_target_args(self, target: build.BuildTarget, compil
28092834
def generate_single_compile(self, target: build.BuildTarget, src,
28102835
is_generated=False, header_deps=None,
28112836
order_deps: T.Optional[T.List[str]] = None,
2812-
extra_args: T.Optional[T.List[str]] = None) -> None:
2837+
extra_args: T.Optional[T.List[str]] = None,
2838+
unity_sources: T.Optional[T.List[mesonlib.FileOrString]] = None) -> None:
28132839
"""
28142840
Compiles C/C++, ObjC/ObjC++, Fortran, and D sources
28152841
"""
@@ -2832,9 +2858,9 @@ def generate_single_compile(self, target: build.BuildTarget, src,
28322858

28332859
# Create introspection information
28342860
if is_generated is False:
2835-
self.create_target_source_introspection(target, compiler, commands, [src], [])
2861+
self.create_target_source_introspection(target, compiler, commands, [src], [], unity_sources)
28362862
else:
2837-
self.create_target_source_introspection(target, compiler, commands, [], [src])
2863+
self.create_target_source_introspection(target, compiler, commands, [], [src], unity_sources)
28382864

28392865
build_dir = self.environment.get_build_dir()
28402866
if isinstance(src, File):
@@ -3360,6 +3386,7 @@ def generate_link(self, target: build.BuildTarget, outname, obj_list, linker: T.
33603386
elem = NinjaBuildElement(self.all_outputs, outname, linker_rule, obj_list, implicit_outs=implicit_outs)
33613387
elem.add_dep(dep_targets + custom_target_libraries)
33623388
elem.add_item('LINK_ARGS', commands)
3389+
self.create_target_linker_introspection(target, linker, commands)
33633390
return elem
33643391

33653392
def get_dependency_filename(self, t):
@@ -3555,13 +3582,11 @@ def generate_ending(self):
35553582
self.add_build(elem)
35563583

35573584
def get_introspection_data(self, target_id: str, target: build.Target) -> T.List[T.Dict[str, T.Union[bool, str, T.List[T.Union[str, T.Dict[str, T.Union[str, T.List[str], bool]]]]]]]:
3558-
if target_id not in self.introspection_data or len(self.introspection_data[target_id]) == 0:
3585+
data = self.introspection_data.get(target_id)
3586+
if not data:
35593587
return super().get_introspection_data(target_id, target)
35603588

3561-
result = []
3562-
for i in self.introspection_data[target_id].values():
3563-
result += [i]
3564-
return result
3589+
return list(data.values())
35653590

35663591

35673592
def _scan_fortran_file_deps(src: Path, srcdir: Path, dirname: Path, tdeps, compiler) -> T.List[str]:

mesonbuild/compilers/compilers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ def get_exelist(self, ccache: bool = True) -> T.List[str]:
600600
return self.exelist.copy() if ccache else self.exelist_no_ccache.copy()
601601

602602
def get_linker_exelist(self) -> T.List[str]:
603-
return self.linker.get_exelist()
603+
return self.linker.get_exelist() if self.linker else self.get_exelist()
604604

605605
@abc.abstractmethod
606606
def get_output_args(self, outputname: str) -> T.List[str]:

mesonbuild/dependencies/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def _process_include_type_kw(cls, kwargs: T.Dict[str, T.Any]) -> str:
9999
return kwargs['include_type']
100100

101101
def __init__(self, type_name: DependencyTypeName, kwargs: T.Dict[str, T.Any]) -> None:
102-
self.name = "null"
102+
self.name = f'dep{id(self)}'
103103
self.version: T.Optional[str] = None
104104
self.language: T.Optional[str] = None # None means C-like
105105
self.is_found = False

mesonbuild/mintro.py

Lines changed: 84 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from contextlib import redirect_stdout
2424
import collections
25+
import dataclasses
2526
import json
2627
import os
2728
from pathlib import Path, PurePath
@@ -31,6 +32,9 @@
3132
from . import build, mesonlib, coredata as cdata
3233
from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstJSONPrinter
3334
from .backend import backends
35+
from .dependencies import Dependency
36+
from . import environment
37+
from .interpreterbase import ObjectHolder
3438
from .mesonlib import OptionKey
3539
from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode
3640

@@ -76,10 +80,12 @@ def get_meson_introspection_types(coredata: T.Optional[cdata.CoreData] = None,
7680
('benchmarks', IntroCommand('List all benchmarks', func=lambda: list_benchmarks(benchmarkdata))),
7781
('buildoptions', IntroCommand('List all build options', func=lambda: list_buildoptions(coredata), no_bd=list_buildoptions_from_source)),
7882
('buildsystem_files', IntroCommand('List files that make up the build system', func=lambda: list_buildsystem_files(builddata, interpreter))),
79-
('dependencies', IntroCommand('List external dependencies', func=lambda: list_deps(coredata), no_bd=list_deps_from_source)),
83+
('compilers', IntroCommand('List used compilers', func=lambda: list_compilers(coredata))),
84+
('dependencies', IntroCommand('List external dependencies', func=lambda: list_deps(coredata, backend), no_bd=list_deps_from_source)),
8085
('scan_dependencies', IntroCommand('Scan for dependencies used in the meson.build file', no_bd=list_deps_from_source)),
8186
('installed', IntroCommand('List all installed files and directories', func=lambda: list_installed(installdata))),
8287
('install_plan', IntroCommand('List all installed files and directories with their details', func=lambda: list_install_plan(installdata))),
88+
('machines', IntroCommand('Information about host, build, and target machines', func=lambda: list_machines(builddata))),
8389
('projectinfo', IntroCommand('Information about projects', func=lambda: list_projinfo(builddata), no_bd=list_projinfo_from_source)),
8490
('targets', IntroCommand('List top level targets', func=lambda: list_targets(builddata, installdata, backend), no_bd=list_targets_from_source)),
8591
('tests', IntroCommand('List all unit tests', func=lambda: list_tests(testdata))),
@@ -250,14 +256,22 @@ def list_targets(builddata: build.Build, installdata: backends.InstallData, back
250256
'name': target.get_basename(),
251257
'id': idname,
252258
'type': target.get_typename(),
253-
'defined_in': os.path.normpath(os.path.join(src_dir, target.subdir, 'meson.build')),
259+
'defined_in': os.path.normpath(os.path.join(src_dir, target.subdir, environment.build_filename)),
254260
'filename': [os.path.join(build_dir, outdir, x) for x in target.get_outputs()],
255261
'build_by_default': target.build_by_default,
256262
'target_sources': backend.get_introspection_data(idname, target),
257263
'extra_files': [os.path.normpath(os.path.join(src_dir, x.subdir, x.fname)) for x in target.extra_files],
258-
'subproject': target.subproject or None
264+
'subproject': target.subproject or None,
265+
'dependencies': [d.name for d in getattr(target, 'external_deps', [])],
259266
}
260267

268+
vs_module_defs = getattr(target, 'vs_module_defs', None)
269+
if vs_module_defs is not None:
270+
t['vs_module_defs'] = vs_module_defs.relative_name()
271+
win_subsystem = getattr(target, 'win_subsystem', None)
272+
if win_subsystem is not None:
273+
t['win_subsystem'] = win_subsystem
274+
261275
if installdata and target.should_install():
262276
t['installed'] = True
263277
ifn = [install_lookuptable.get(x, [None]) for x in target.get_outputs()]
@@ -343,6 +357,23 @@ def list_buildsystem_files(builddata: build.Build, interpreter: Interpreter) ->
343357
filelist = [PurePath(src_dir, x).as_posix() for x in filelist]
344358
return filelist
345359

360+
def list_compilers(coredata: cdata.CoreData) -> T.Dict[str, T.Dict[str, T.Dict[str, str]]]:
361+
compilers: T.Dict[str, T.Dict[str, T.Dict[str, str]]] = {}
362+
for machine in ('host', 'build'):
363+
compilers[machine] = {}
364+
for language, compiler in getattr(coredata.compilers, machine).items():
365+
compilers[machine][language] = {
366+
'id': compiler.get_id(),
367+
'exelist': compiler.get_exelist(),
368+
'linker_exelist': compiler.get_linker_exelist(),
369+
'file_suffixes': compiler.file_suffixes,
370+
'default_suffix': compiler.get_default_suffix(),
371+
'version': compiler.version,
372+
'full_version': compiler.full_version,
373+
'linker_id': compiler.get_linker_id(),
374+
}
375+
return compilers
376+
346377
def list_deps_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str, T.Union[str, bool]]]:
347378
result = [] # type: T.List[T.Dict[str, T.Union[str, bool]]]
348379
for i in intr.dependencies:
@@ -356,15 +387,48 @@ def list_deps_from_source(intr: IntrospectionInterpreter) -> T.List[T.Dict[str,
356387
result += [{k: v for k, v in i.items() if k in keys}]
357388
return result
358389

359-
def list_deps(coredata: cdata.CoreData) -> T.List[T.Dict[str, T.Union[str, T.List[str]]]]:
360-
result = [] # type: T.List[T.Dict[str, T.Union[str, T.List[str]]]]
390+
def list_deps(coredata: cdata.CoreData, backend: backends.Backend) -> T.List[T.Dict[str, T.Union[str, T.List[str]]]]:
391+
result: T.Dict[str, T.Dict[str, T.Union[str, T.List[str]]]] = {}
392+
393+
def _src_to_str(src_file: T.Union[mesonlib.FileOrString, build.CustomTarget, build.StructuredSources, build.CustomTargetIndex, build.GeneratedList]) -> T.List[str]:
394+
if isinstance(src_file, str):
395+
return [src_file]
396+
if isinstance(src_file, mesonlib.File):
397+
return [src_file.absolute_path(backend.source_dir, backend.build_dir)]
398+
if isinstance(src_file, (build.CustomTarget, build.CustomTargetIndex, build.GeneratedList)):
399+
return src_file.get_outputs()
400+
if isinstance(src_file, build.StructuredSources):
401+
return [f for s in src_file.as_list() for f in _src_to_str(s)]
402+
raise mesonlib.MesonBugException(f'Invalid file type {type(src_file)}.')
403+
404+
def _create_result(d: Dependency, varname: T.Optional[str] = None) -> T.Dict[str, T.Any]:
405+
return {
406+
'name': d.name,
407+
'type': d.type_name,
408+
'version': d.get_version(),
409+
'compile_args': d.get_compile_args(),
410+
'link_args': d.get_link_args(),
411+
'include_directories': [i for idirs in d.get_include_dirs() for i in idirs.to_string_list(backend.source_dir)],
412+
'sources': [f for s in d.get_sources() for f in _src_to_str(s)],
413+
'extra_files': [f for s in d.get_extra_files() for f in _src_to_str(s)],
414+
'deps': [e.name for e in d.ext_deps],
415+
'meson_variables': [varname] if varname else [],
416+
}
417+
361418
for d in coredata.deps.host.values():
362419
if d.found():
363-
result += [{'name': d.name,
364-
'version': d.get_version(),
365-
'compile_args': d.get_compile_args(),
366-
'link_args': d.get_link_args()}]
367-
return result
420+
result[d.name] = _create_result(d)
421+
422+
for varname, holder in backend.interpreter.variables.items():
423+
if isinstance(holder, ObjectHolder):
424+
d = holder.held_object
425+
if isinstance(d, Dependency) and d.found():
426+
if d.name in result:
427+
T.cast(T.List[str], result[d.name]['meson_variables']).append(varname)
428+
else:
429+
result[d.name] = _create_result(d, varname)
430+
431+
return list(result.values())
368432

369433
def get_test_list(testdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
370434
result = [] # type: T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]
@@ -396,6 +460,16 @@ def list_tests(testdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[st
396460
def list_benchmarks(benchdata: T.List[backends.TestSerialisation]) -> T.List[T.Dict[str, T.Union[str, int, T.List[str], T.Dict[str, str]]]]:
397461
return get_test_list(benchdata)
398462

463+
def list_machines(builddata: build.Build) -> T.Dict[str, T.Dict[str, T.Union[str, bool]]]:
464+
machines: T.Dict[str, T.Dict[str, T.Union[str, bool]]] = {}
465+
for m in ('host', 'build', 'target'):
466+
machine = getattr(builddata.environment.machines, m)
467+
machines[m] = dataclasses.asdict(machine)
468+
machines[m]['is_64_bit'] = machine.is_64_bit
469+
machines[m]['exe_suffix'] = machine.get_exe_suffix()
470+
machines[m]['object_suffix'] = machine.get_object_suffix()
471+
return machines
472+
399473
def list_projinfo(builddata: build.Build) -> T.Dict[str, T.Union[str, T.List[T.Dict[str, str]]]]:
400474
result = {'version': builddata.project_version,
401475
'descriptive_name': builddata.project_name,

0 commit comments

Comments
 (0)