diff --git a/refresh.template.py b/refresh.template.py index 6604621..e028c99 100644 --- a/refresh.template.py +++ b/refresh.template.py @@ -89,6 +89,35 @@ def _print_header_finding_warning_once(): _print_header_finding_warning_once.has_logged = False +@functools.lru_cache +def _get_bazel_version(): + """Gets the Bazel version as a tuple of (major, minor, patch). + + The rolling release and the release candidate are treated as the LTS release. + E.g. both 7.0.0-pre.XXXXXXXX.X and 7.0.0rc1 are treated as 7.0.0. + If the version can't be determined, returns (0, 0, 0). + """ + bazel_version_process = subprocess.run( + ['bazel', 'version'], + capture_output=True, + encoding=locale.getpreferredencoding(), + check=True, # Should always succeed. + ) + + version = '' + for line in bazel_version_process.stdout.splitlines(): + line = line.strip() + if line.startswith('Build label: '): + version = line[len('Build label: '):] + + match = re.search(r'^(\d+)\.(\d+)\.(\d+)', version) + if not match: + log_warning(f">>> Failed to get Bazel version.\nPlease file an issue with the following log:\n", bazel_version_process.stdout) + return (0, 0, 0) + + return tuple(int(match.group(i)) for i in range(1, 4)) + + @functools.lru_cache def _get_bazel_cached_action_keys(): """Gets the set of actionKeys cached in bazel-out.""" @@ -727,6 +756,19 @@ def _apple_platform_patch(compile_args: list[str]): return compile_args +def _get_sysroot(args: typing.List[str]): + """Get path to sysroot from command line arguments.""" + for idx, arg in enumerate(args): + if arg == '--sysroot' or arg == '-isysroot': + if idx + 1 < len(args): + return pathlib.PurePath(args[idx + 1]) + elif arg.startswith('--sysroot='): + return pathlib.PurePath(arg[len('--sysroot='):]) + elif arg.startswith('-isysroot'): + return pathlib.PurePath(arg[len('-isysroot'):]) + return None + + def _emscripten_platform_patch(compile_action): """De-Bazel the command into something clangd can parse. @@ -737,6 +779,13 @@ def _emscripten_platform_patch(compile_action): return compile_action.arguments workspace_absolute = pathlib.PurePath(os.environ["BUILD_WORKSPACE_DIRECTORY"]) + sysroot = _get_sysroot(compile_action.arguments) + assert sysroot, f'Emscripten sysroot not detected in CMD: {compile_action.arguments}' + + def get_workspace_root(path_from_execroot: pathlib.PurePath): + if path_from_execroot.parts[0] != 'external': + return pathlib.PurePath('.') + return pathlib.PurePath('external') / path_from_execroot.parts[1] environment = compile_action.environmentVariables.copy() environment['EXT_BUILD_ROOT'] = str(workspace_absolute) @@ -744,6 +793,10 @@ def _emscripten_platform_patch(compile_action): environment['EM_COMPILER_WRAPPER'] = str(pathlib.PurePath({print_args_executable})) if 'PATH' not in environment: environment['PATH'] = os.environ['PATH'] + if 'EM_BIN_PATH' not in environment: + environment['EM_BIN_PATH'] = str(get_workspace_root(sysroot)) + if 'EM_CONFIG_PATH' not in environment: + environment['EM_CONFIG_PATH'] = str(get_workspace_root(emcc_driver) / 'emscripten_toolchain' / 'emscripten_config') # We run the emcc process with the environment variable EM_COMPILER_WRAPPER to intercept the command line arguments passed to `clang`. emcc_process = subprocess.run( @@ -1143,13 +1196,17 @@ def _get_commands(target: str, flags: str): # That's all well and good, but param files would prevent us from seeing compile actions before the param files had been generated by compilation. # Since clangd has no such length limit, we'll disable param files for our aquery run. '--features=-compiler_param_file', - '--host_features=-compiler_param_file', # Disable layering_check during, because it causes large-scale dependence on generated module map files that prevent header extraction before their generation # For more context, see https://github.com/hedronvision/bazel-compile-commands-extractor/issues/83 # If https://github.com/clangd/clangd/issues/123 is resolved and we're not doing header extraction, we could try removing this, checking that there aren't erroneous red squigglies squigglies before the module maps are generated. # If Bazel starts supporting modules (https://github.com/bazelbuild/bazel/issues/4005), we'll probably need to make changes that subsume this. '--features=-layering_check', - ] + additional_flags + ] + + if _get_bazel_version() >= (6, 1, 0): + aquery_args += ['--host_features=-compiler_param_file'] + + aquery_args += additional_flags aquery_process = subprocess.run( aquery_args, diff --git a/refresh_compile_commands.bzl b/refresh_compile_commands.bzl index 5ce7461..5231721 100644 --- a/refresh_compile_commands.bzl +++ b/refresh_compile_commands.bzl @@ -82,7 +82,7 @@ def refresh_compile_commands( # Make any package-relative labels absolute targets = { - target if target.startswith("/") or target.startswith("@") else "@{}//{}:{}".format(native.repository_name(), native.package_name(), target.removeprefix(":")): flags for target, flags in targets.items() + target if target.startswith("/") or target.startswith("@") else "{}//{}:{}".format(native.repository_name(), native.package_name(), target.removeprefix(":")): flags for target, flags in targets.items() } # Generate the core, runnable python script from refresh.template.py