diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 9a377d49b..b36b98c9d 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -20,11 +20,10 @@ from .. import mesonlib from .. import mlog import json import subprocess -from ..dependencies import base from ..mesonlib import MesonException, OrderedSet from ..mesonlib import classify_unity_sources from ..mesonlib import File -from ..compilers import CompilerArgs, VisualStudioCCompiler, compilers +from ..compilers import CompilerArgs, VisualStudioCCompiler from collections import OrderedDict import shlex from functools import lru_cache @@ -159,7 +158,6 @@ class Backend: self.processed_targets = {} self.build_to_src = mesonlib.relpath(self.environment.get_source_dir(), self.environment.get_build_dir()) - self.introspect_data_cache = None # Cache to speed up get_introspection_data def get_target_filename(self, t): if isinstance(t, build.CustomTarget): @@ -1166,163 +1164,7 @@ class Backend: This is a limited fallback / reference implementation. The backend should override this method. ''' - if not self.introspect_data_cache: - self.introspect_data_cache = {'targets': {}, 'dependencies': {}} - - reg = re.compile(r'-I(.*)') - - def extract_dependency_infromation(dep): - inc_dirs = [] - args = [] - if isinstance(dep, base.Dependency): - reg = re.compile(r'-I(.*)') - for i in dep.get_compile_args(): - match = reg.match(i) - if match: - inc_dirs += [match.group(1)] - else: - args += [i] - - return inc_dirs, args - - def process_target(tgt, src_root, build_root): - if isinstance(tgt, build.BuildTarget): - # First check if the target is cached - tgtid = tgt.get_id() - if tgtid in self.introspect_data_cache['targets']: - c_tgt = self.introspect_data_cache['targets'][tgtid] - return c_tgt['inc_dirs'], c_tgt['dep_args'], c_tgt['extra_args'] - - # The build directory is always in the include directories - absbase_src = os.path.join(src_root, tgt.subdir) - absbase_build = os.path.join(build_root, tgt.subdir) - inc_dirs = [absbase_src, absbase_build] - dep_args = [] - extra_args = {} - - # Handle include directories - for i in tgt.include_dirs: - if isinstance(i, build.IncludeDirs): - for j in i.get_incdirs(): - abs_src = os.path.join(absbase_src, i.get_curdir(), j) - abs_build = os.path.join(absbase_build, i.get_curdir(), j) - - if os.path.isdir(abs_src): - inc_dirs += [abs_src] - - if os.path.isdir(abs_build): - inc_dirs += [abs_build] - - # Handle dependencies - for i in tgt.external_deps: - if not isinstance(i, base.Dependency): - continue - - did = id(i) - if did in self.introspect_data_cache['dependencies']: - c_entry = self.introspect_data_cache['dependencies'][did] - inc_dirs += c_entry['dep_inc_dirs'] - dep_args += c_entry['dep_cur_args'] - continue - - dep_inc_dirs = [] - dep_cur_args = [] - - for i in i.get_compile_args(): - match = reg.match(i) - if match: - dep_inc_dirs += [match.group(1)] - else: - dep_cur_args += [i] - - self.introspect_data_cache['dependencies'][did] = { - 'dep_inc_dirs': dep_inc_dirs, - 'dep_cur_args': dep_cur_args - } - inc_dirs += dep_inc_dirs - dep_args += dep_cur_args - - # Check for language specific extra args - for i, comp in tgt.compilers.items(): - if isinstance(comp, compilers.Compiler): - if i not in extra_args: - extra_args[i] = [] - - extra_args[i] += tgt.get_extra_args(i) - extra_args[i] += self.build.get_global_args(comp, tgt.is_cross) - extra_args[i] += self.build.get_project_args(comp, tgt.subproject, tgt.is_cross) - - # Recursively check the other targets - for i in tgt.link_targets: - t_inc_dirs, t_dep_args, t_extra_args = process_target(i, src_root, build_root) - inc_dirs += t_inc_dirs - dep_args += t_dep_args - for ind, arglist in t_extra_args.items(): - if ind in extra_args: - extra_args[ind] += arglist - else: - extra_args[ind] = arglist - - # Update the cache - self.introspect_data_cache['targets'][tgtid] = { - 'inc_dirs': inc_dirs, - 'dep_args': dep_args, - 'extra_args': extra_args - } - - return inc_dirs, dep_args, extra_args - - src_root = self.build.environment.get_source_dir() - build_root = self.build.environment.get_build_dir() - sources = {} - - if isinstance(target, build.BuildTarget): - inc_dirs, dep_args, extra_args = process_target(target, src_root, build_root) - - # Add the dep_args, sort and remove duplicates - for i in extra_args: - extra_args[i] += dep_args - extra_args[i] = list(sorted(list(set(extra_args[i])))) - - # Remove duplicates, sort and make paths pretty - inc_dirs = list(sorted(list(set(inc_dirs)))) - inc_dirs = list(map(lambda x: os.path.realpath(x), inc_dirs)) - - comp_list = target.compilers.values() - source_list = target.sources + target.extra_files - source_list = list(map(lambda x: (mesonlib.get_compiler_for_source(comp_list, x, True), x), source_list)) - - for comp, src in source_list: - if isinstance(src, mesonlib.File): - src = os.path.join(src.subdir, src.fname) - if isinstance(comp, compilers.Compiler) and isinstance(src, str): - lang = comp.get_language() - if lang not in sources: - parameters = [] - - # Generate include directories - # Not all compilers have the get_include_args method - get_include_args = getattr(comp, 'get_include_args', None) - if callable(get_include_args): - for i in inc_dirs: - parameters += comp.get_include_args(i, False) - - # Extra args - if lang in extra_args: - parameters += extra_args[lang] - - sources[lang] = { - 'compiler': comp.get_exelist(), - 'parameters': parameters, - 'source_files': [] - } - - sources[lang]['source_files'] += [src] - elif comp is None and isinstance(src, str): - if 'unknown' not in sources: - sources['unknown'] = {'compiler': [], 'parameters': [], 'source_files': []} - sources['unknown']['source_files'] += [src] - elif isinstance(target, build.CustomTarget): + if isinstance(target, (build.CustomTarget, build.BuildTarget)): source_list_raw = target.sources + target.extra_files source_list = [] for i in source_list_raw: @@ -1331,12 +1173,16 @@ class Backend: elif isinstance(i, str): source_list += [i] - sources['unknown'] = {'compiler': [], 'parameters': [], 'source_files': source_list} - - # Convert the dict to a list and add the language key. - # This list approach will also work if the gurantee is removed that all - # files in a target are compiled with the same parameters - # see https://github.com/mesonbuild/meson/pull/4547 - sources = list(map(lambda x: {'language': x[0], **x[1]}, sources.items())) - - return sources + return [{ + 'language': 'unknown', + 'compiler': [], + 'parameters': [], + 'source_files': source_list + }] + + return [{ + 'language': 'unknown', + 'compiler': [], + 'parameters': [], + 'source_files': [] + }] diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index ef029405e..98c2366d6 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -268,12 +268,10 @@ class File: def relative_name(self): return os.path.join(self.subdir, self.fname) -def get_compiler_for_source(compilers, src, canfail=False): +def get_compiler_for_source(compilers, src): for comp in compilers: if comp.can_compile(src): return comp - if canfail: - return None raise MesonException('No specified compiler can handle file {!s}'.format(src)) def classify_unity_sources(compilers, sources): diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index 6768070ed..97a7c9474 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -100,6 +100,13 @@ def list_installed(installdata): def list_targets(builddata: build.Build, installdata, backend: backends.Backend): tlist = [] + + # Fast lookup table for installation files + intall_lookuptable = {} + for i in installdata.targets: + outname = os.path.join(installdata.prefix, i.outdir, os.path.basename(i.fname)) + intall_lookuptable[os.path.basename(i.fname)] = str(pathlib.PurePath(outname)) + for (idname, target) in builddata.get_targets().items(): if not isinstance(target, build.Target): raise RuntimeError('Something weird happened. File a bug.') @@ -121,7 +128,12 @@ def list_targets(builddata: build.Build, installdata, backend: backends.Backend) if installdata and target.should_install(): t['installed'] = True - t['install_filename'] = determine_installed_path(target, installdata) + t['install_filename'] = [] + + for i in target.outputs: + fname = intall_lookuptable.get(i) + if i is not None: + t['install_filename'] += [fname] else: t['installed'] = False tlist.append(t)