Ninja backend target introspection

pull/4547/head
Daniel Mensinger 6 years ago
parent b9c4913cf0
commit 7691b0460c
No known key found for this signature in database
GPG Key ID: 54DD94C131E277D4
  1. 14
      mesonbuild/backend/backends.py
  2. 127
      mesonbuild/backend/ninjabackend.py
  3. 2
      mesonbuild/mintro.py
  4. 7
      run_unittests.py

@ -1158,7 +1158,8 @@ class Backend:
"language": "<LANG>",
"compiler": ["result", "of", "comp.get_exelist()"],
"parameters": ["list", "of", "compiler", "parameters],
"source_files": ["list", "of", "all", "<LANG>", "source", "files"]
"sources": ["list", "of", "all", "<LANG>", "source", "files"],
"generated_sources": ["list", "of", "generated", "source", "files"]
}
]
@ -1169,20 +1170,23 @@ class Backend:
source_list = []
for i in source_list_raw:
if isinstance(i, mesonlib.File):
source_list += [os.path.join(i.subdir, i.fname)]
source_list += [i.absolute_path(self.environment.get_source_dir(), self.environment.get_build_dir())]
elif isinstance(i, str):
source_list += [i]
source_list += [os.path.join(self.environment.get_source_dir(), i)]
source_list = list(map(lambda x: os.path.normpath(x), source_list))
return [{
'language': 'unknown',
'compiler': [],
'parameters': [],
'source_files': source_list
'sources': source_list,
'generated_sources': []
}]
return [{
'language': 'unknown',
'compiler': [],
'parameters': [],
'source_files': []
'sources': [],
'generated_sources': []
}]

@ -150,6 +150,8 @@ class NinjaBackend(backends.Backend):
self.ninja_filename = 'build.ninja'
self.fortran_deps = {}
self.all_outputs = {}
self.introspection_data = {}
self._intro_last_index = 0
def create_target_alias(self, to_target, outfile):
# We need to use aliases for targets that might be used as directory
@ -321,6 +323,73 @@ int dummy;
return False
return True
def create_target_source_introspection(self, target, comp, parameters, sources, generated_sources):
'''
Adds the source file introspection information for a language of a target
Internal introspection storage formart:
self.introspection_data = {
'<target ID>': [
{
'language: 'lang',
'compiler': ['comp', 'exe', 'list'],
'parameters': ['UNIQUE', 'parameter', 'list'],
'sources': [],
'generated_sources': [],
'id_hash': 634523234445 # Internal unique hash to identify a compiler / language / paramerter combo
}
]
}
'''
build_dir = self.environment.get_build_dir()
id = target.get_id()
lang = comp.get_language()
tgt = self.introspection_data[id]
id_hash = hash((lang, CompilerArgs))
src_block = None
# Find an existing entry or create a new one
# ... first check the last used index
if self._intro_last_index < len(tgt):
tmp = tgt[self._intro_last_index]
if tmp['id_hash'] == id_hash:
src_block = tmp
# ... check all entries
if src_block is None:
for idx, i in enumerate(tgt):
if i['id_hash'] == id_hash:
src_block = i
self._intro_last_index = idx
break
# ... create a new one
if src_block is None:
# Convert parameters
if isinstance(parameters, CompilerArgs):
parameters = parameters.to_native(copy=True)
for idx, i in enumerate(parameters):
if i[:2] == '-I' or i[:2] == '/I' or i[:2] == '-L':
parameters[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
if target.is_cross:
parameters += comp.get_cross_extra_flags(self.environment, False)
# The new entry
src_block = {
'language': lang,
'compiler': comp.get_exelist(),
'parameters': parameters,
'sources': [],
'generated_sources': [],
'id_hash': id_hash
}
self._intro_last_index = len(tgt)
tgt.append(src_block)
# Make source files absolute
sources = [x.rel_to_builddir(self.build_to_src) if isinstance(x, File) else x for x in sources]
sources = [os.path.normpath(os.path.join(build_dir, x)) for x in sources]
generated_sources = [x.rel_to_builddir(self.build_to_src) if isinstance(x, File) else x for x in generated_sources]
generated_sources = [os.path.normpath(os.path.join(build_dir, x)) for x in generated_sources]
# Add the source files
src_block['sources'] += sources
src_block['generated_sources'] += generated_sources
def generate_target(self, target, outfile):
if isinstance(target, build.CustomTarget):
self.generate_custom_target(target, outfile)
@ -330,6 +399,8 @@ int dummy;
if name in self.processed_targets:
return
self.processed_targets[name] = True
# Initialize an empty introspection source list
self.introspection_data[name] = []
# Generate rules for all dependency targets
self.process_target_dependencies(target, outfile)
# If target uses a language that cannot link to C objects,
@ -770,14 +841,16 @@ int dummy;
# Add possible java generated files to src list
generated_sources = self.get_target_generated_sources(target)
gen_src_list = []
for rel_src, gensrc in generated_sources.items():
dirpart, fnamepart = os.path.split(rel_src)
raw_src = File(True, dirpart, fnamepart)
if rel_src.endswith('.java'):
src_list.append(raw_src)
gen_src_list.append(raw_src)
for src in src_list:
plain_class_path = self.generate_single_java_compile(src, target, compiler, outfile)
compile_args = self.determine_single_java_compile_args(target, compiler)
for src in src_list + gen_src_list:
plain_class_path = self.generate_single_java_compile(src, target, compiler, compile_args, outfile)
class_list.append(plain_class_path)
class_dep_list = [os.path.join(self.get_target_private_dir(target), i) for i in class_list]
manifest_path = os.path.join(self.get_target_private_dir(target), 'META-INF', 'MANIFEST.MF')
@ -803,6 +876,8 @@ int dummy;
elem.add_dep(class_dep_list)
elem.add_item('ARGS', commands)
elem.write(outfile)
# Create introspection information
self.create_target_source_introspection(target, compiler, compile_args, src_list, gen_src_list)
def generate_cs_resource_tasks(self, target, outfile):
args = []
@ -856,10 +931,11 @@ int dummy;
else:
outputs = [outname_rel]
generated_sources = self.get_target_generated_sources(target)
generated_rel_srcs = []
for rel_src in generated_sources.keys():
dirpart, fnamepart = os.path.split(rel_src)
if rel_src.lower().endswith('.cs'):
rel_srcs.append(os.path.normpath(rel_src))
generated_rel_srcs.append(os.path.normpath(rel_src))
deps.append(os.path.normpath(rel_src))
for dep in target.get_external_deps():
@ -867,19 +943,15 @@ int dummy;
commands += self.build.get_project_args(compiler, target.subproject, target.is_cross)
commands += self.build.get_global_args(compiler, target.is_cross)
elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs)
elem = NinjaBuildElement(self.all_outputs, outputs, 'cs_COMPILER', rel_srcs + generated_rel_srcs)
elem.add_dep(deps)
elem.add_item('ARGS', commands)
elem.write(outfile)
self.generate_generator_list_rules(target, outfile)
self.create_target_source_introspection(target, compiler, commands, rel_srcs, generated_rel_srcs)
def generate_single_java_compile(self, src, target, compiler, outfile):
deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets]
generated_sources = self.get_target_generated_sources(target)
for rel_src, gensrc in generated_sources.items():
if rel_src.endswith('.java'):
deps.append(rel_src)
def determine_single_java_compile_args(self, target, compiler):
args = []
args += compiler.get_buildtype_args(self.get_option_for_target('buildtype', target))
args += self.build.get_global_args(compiler, target.is_cross)
@ -894,6 +966,14 @@ int dummy;
for idir in i.get_incdirs():
sourcepath += os.path.join(self.build_to_src, i.curdir, idir) + os.pathsep
args += ['-sourcepath', sourcepath]
return args
def generate_single_java_compile(self, src, target, compiler, args, outfile):
deps = [os.path.join(self.get_target_dir(l), l.get_filename()) for l in target.link_targets]
generated_sources = self.get_target_generated_sources(target)
for rel_src, gensrc in generated_sources.items():
if rel_src.endswith('.java'):
deps.append(rel_src)
rel_src = src.rel_to_builddir(self.build_to_src)
plain_class_path = src.fname[:-4] + 'class'
rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path)
@ -1102,6 +1182,7 @@ int dummy;
element.add_item('ARGS', args)
element.add_dep(extra_dep_files)
element.write(outfile)
self.create_target_source_introspection(target, valac, args, all_files, [])
return other_src[0], other_src[1], vala_c_src
def generate_rust_target(self, target, outfile):
@ -1193,6 +1274,7 @@ int dummy;
element.write(outfile)
if isinstance(target, build.SharedLibrary):
self.generate_shsym(outfile, target)
self.create_target_source_introspection(target, rustc, args, [main_rust_file], [])
def swift_module_file_name(self, target):
return os.path.join(self.get_target_private_dir(target),
@ -1241,12 +1323,14 @@ int dummy;
module_name = self.target_swift_modulename(target)
swiftc = target.compilers['swift']
abssrc = []
relsrc = []
abs_headers = []
header_imports = []
for i in target.get_sources():
if swiftc.can_compile(i):
relsrc = i.rel_to_builddir(self.build_to_src)
abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc))
rels = i.rel_to_builddir(self.build_to_src)
abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), rels))
relsrc.append(rels)
abssrc.append(abss)
elif self.environment.is_header(i):
relh = i.rel_to_builddir(self.build_to_src)
@ -1330,6 +1414,8 @@ int dummy;
elem.write(outfile)
else:
raise MesonException('Swift supports only executable and static library targets.')
# Introspection information
self.create_target_source_introspection(target, swiftc, compile_args + header_imports + module_includes, relsrc, rel_generated)
def generate_static_link_rules(self, is_cross, outfile):
num_pools = self.environment.coredata.backend_options['backend_max_links'].value
@ -2049,6 +2135,12 @@ rule FORTRAN_DEP_HACK%s
commands = self._generate_single_compile(target, compiler, is_generated)
commands = CompilerArgs(commands.compiler, commands)
# Create introspection information
if is_generated is False:
self.create_target_source_introspection(target, compiler, commands, [src], [])
else:
self.create_target_source_introspection(target, compiler, commands, [], [src])
build_dir = self.environment.get_build_dir()
if isinstance(src, File):
rel_src = src.rel_to_builddir(self.build_to_src)
@ -2663,6 +2755,15 @@ rule FORTRAN_DEP_HACK%s
elem = NinjaBuildElement(self.all_outputs, deps, 'phony', '')
elem.write(outfile)
def get_introspection_data(self, target_id, target):
if target_id not in self.introspection_data or len(self.introspection_data[target_id]) == 0:
return super().get_introspection_data(target_id, target)
result = self.introspection_data[target_id].copy()
for i in result:
i.pop('id_hash')
return result
def load(build_dir):
filename = os.path.join(build_dir, 'meson-private', 'install.dat')
with open(filename, 'rb') as f:

@ -272,7 +272,7 @@ def list_target_files(target_name, targets):
raise RuntimeError('Target with the ID "{}" could not be found'.format(target_name))
for i in tgt['sources']:
result += i['source_files']
result += i['sources'] + i['generated_sources']
return ('target_files', result)

@ -2562,6 +2562,7 @@ int main(int argc, char **argv) {
for t in t_intro:
id = t['id']
tf_intro = self.introspect(['--target-files', id])
tf_intro = list(map(lambda x: os.path.relpath(x, testdir), tf_intro))
self.assertEqual(tf_intro, expected[id])
self.wipe()
@ -2576,6 +2577,9 @@ int main(int argc, char **argv) {
for t in t_intro:
id = t['id']
tf_intro = self.introspect(['--target-files', id])
print(tf_intro)
tf_intro = list(map(lambda x: os.path.relpath(x, testdir), tf_intro))
print(tf_intro)
self.assertEqual(tf_intro, expected[id])
self.wipe()
@ -3179,7 +3183,8 @@ recommended as it is not supported on some platforms''')
('language', str),
('compiler', list),
('parameters', list),
('source_files', list),
('sources', list),
('generated_sources', list),
]
# First load all files

Loading…
Cancel
Save