diff --git a/crosstool/BUILD.tpl b/crosstool/BUILD.tpl index 830a94c..93cac75 100644 --- a/crosstool/BUILD.tpl +++ b/crosstool/BUILD.tpl @@ -51,6 +51,7 @@ cc_toolchain_suite( ":make_hashed_objlist.py", ":wrapped_clang", ":wrapped_clang_pp", + "@build_bazel_apple_support_index_import//:index-import", ":xcrunwrapper.sh", ], ) diff --git a/crosstool/cc_toolchain_config.bzl b/crosstool/cc_toolchain_config.bzl index 8d36f64..c33d3aa 100644 --- a/crosstool/cc_toolchain_config.bzl +++ b/crosstool/cc_toolchain_config.bzl @@ -2154,6 +2154,50 @@ def _impl(ctx): ], ) + indexstore_files_feature = feature( + name = "indexstore_files", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.cpp_header_parsing, + ], + flag_groups = [ + flag_group( + flags = ["-index-store-path", "%{indexstore_files}", "-index-ignore-system-symbols"], + expand_if_available = "indexstore_files", + ), + ], + ), + ], + ) + + use_global_indexstore_feature = feature( + name = "use_global_indexstore", + env_sets = [ + env_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.cpp_header_parsing, + ], + env_entries = [ + env_entry( + key = "GLOBAL_INDEXSTORE", + value = "true", + ), + ], + ), + ], + ) + preprocessor_defines_feature = feature( name = "preprocessor_defines", enabled = True, @@ -2472,6 +2516,8 @@ def _impl(ctx): sysroot_feature, dependency_file_feature, serialized_diagnostics_file_feature, + indexstore_files_feature, + use_global_indexstore_feature, pic_feature, per_object_debug_info_feature, preprocessor_defines_feature, diff --git a/crosstool/osx_cc_configure.bzl b/crosstool/osx_cc_configure.bzl index 3b9678a..574f644 100644 --- a/crosstool/osx_cc_configure.bzl +++ b/crosstool/osx_cc_configure.bzl @@ -136,6 +136,7 @@ def configure_osx_toolchain(repository_ctx): wrapped_clang_src_path = str(repository_ctx.path( Label("@build_bazel_apple_support//crosstool:wrapped_clang.cc"), )) + index_import = Label("@build_bazel_apple_support_index_import//:index-import") xcode_toolchains = [] xcodeloc_err = "" @@ -162,6 +163,7 @@ def configure_osx_toolchain(repository_ctx): ) repository_ctx.symlink(xcrunwrapper, "xcrunwrapper.sh") repository_ctx.symlink(libtool, "libtool") + repository_ctx.symlink(index_import, "index-import") repository_ctx.symlink(make_hashed_objlist, "make_hashed_objlist.py") repository_ctx.symlink(cc_toolchain_config, "cc_toolchain_config.bzl") _compile_cc_file(repository_ctx, libtool_check_unique_src_path, "libtool_check_unique") diff --git a/crosstool/wrapped_clang.cc b/crosstool/wrapped_clang.cc index a71464d..dc50365 100644 --- a/crosstool/wrapped_clang.cc +++ b/crosstool/wrapped_clang.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,14 @@ const char *Basename(const char *filepath) { return base ? (base + 1) : filepath; } +// Returns the dir name of the given filepath. For example, given +// /foo/bar/baz.txt, returns '/foo/bar'. +const std::string Dirname(const char *filepath) { + std::string path = std::string(filepath); + std::string dirname = path.substr(0, path.find_last_of('/')); + return dirname; +} + // Unescape and unquote an argument read from a line of a response file. static std::string Unescape(const std::string &arg) { std::string result; @@ -260,14 +269,16 @@ static std::unique_ptr WriteResponseFile( void ProcessArgument(const std::string arg, const std::string developer_dir, const std::string sdk_root, const std::string cwd, bool relative_ast_path, std::string &linked_binary, - std::string &dsym_path, std::string toolchain_path, - std::function consumer); + std::string &dsym_path, std::string &original_indexstore_path, + std::string &global_indexstore_path, std::string &output_file_path, + std::string toolchain_path, std::function consumer); bool ProcessResponseFile(const std::string arg, const std::string developer_dir, const std::string sdk_root, const std::string cwd, bool relative_ast_path, std::string &linked_binary, - std::string &dsym_path, std::string toolchain_path, - std::function consumer) { + std::string &dsym_path, std::string &original_indexstore_path, + std::string &global_indexstore_path, std::string &output_file_path, + std::string toolchain_path, std::function consumer) { auto path = arg.substr(1); std::ifstream original_file(path); // Ignore non-file args such as '@loader_path/...' @@ -280,7 +291,8 @@ bool ProcessResponseFile(const std::string arg, const std::string developer_dir, // Arguments in response files might be quoted/escaped, so we need to // unescape them ourselves. ProcessArgument(Unescape(arg_from_file), developer_dir, sdk_root, cwd, - relative_ast_path, linked_binary, dsym_path, + relative_ast_path, linked_binary, dsym_path, + original_indexstore_path, global_indexstore_path, output_file_path, toolchain_path, consumer); } @@ -336,12 +348,14 @@ std::string GetToolchainPath(const std::string &toolchain_id) { void ProcessArgument(const std::string arg, const std::string developer_dir, const std::string sdk_root, const std::string cwd, bool relative_ast_path, std::string &linked_binary, - std::string &dsym_path, std::string toolchain_path, - std::function consumer) { + std::string &dsym_path, std::string &original_indexstore_path, + std::string &global_indexstore_path, std::string &output_file_path, + std::string toolchain_path, std::function consumer) { auto new_arg = arg; if (arg[0] == '@') { if (ProcessResponseFile(arg, developer_dir, sdk_root, cwd, relative_ast_path, linked_binary, dsym_path, + original_indexstore_path, global_indexstore_path, output_file_path, toolchain_path, consumer)) { return; } @@ -374,11 +388,31 @@ void ProcessArgument(const std::string arg, const std::string developer_dir, } } + size_t extension_position = arg.find_last_of("."); + + // global_indexstore_path should be non-empty when global indexstore feature is enabled. + // If enabled, replace --index-store-path flag value with global indexstore path and save the + // original indexstore path for copying back later. + if (!global_indexstore_path.empty()) { + if (extension_position != std::string::npos && arg.substr(extension_position) == ".indexstore") { + original_indexstore_path = cwd + "/" + arg; + new_arg = global_indexstore_path; + } + if (extension_position != std::string::npos && arg.substr(extension_position) == ".o") { + output_file_path = cwd + "/" + arg; + } + } + consumer(new_arg); } } // namespace +inline bool path_exists(const std::string& path) { + struct stat buffer; + return (stat (path.c_str(), &buffer) == 0); +} + int main(int argc, char *argv[]) { std::string tool_name; @@ -403,8 +437,23 @@ int main(int argc, char *argv[]) { std::string developer_dir = GetMandatoryEnvVar("DEVELOPER_DIR"); std::string sdk_root = GetMandatoryEnvVar("SDKROOT"); std::string linked_binary, dsym_path; + // variables for indexstore binaries and outputs + std::string original_indexstore_path, global_indexstore_path, output_file_path, index_import_path; const std::string cwd = GetCurrentDirectory(); + + // check if global indexstore feature is used. If true, use global indexstore for all compile actions + // passing --index-store-path flag and copy indexstore data corresponding to the action output file to + // action specific value of --index-store-path flag. This change is modeled after a rules_swift change + // (https://github.com/bazelbuild/rules_swift/pull/567) + bool use_global_indexstore = getenv("GLOBAL_INDEXSTORE") != nullptr; + global_indexstore_path = ""; + index_import_path = ""; + if (use_global_indexstore) { + global_indexstore_path = cwd + "/" + "bazel-out" + "/" + "_global_index_store"; + index_import_path = cwd + "/" + Dirname(argv[0]) + "/" + "index-import"; + } + std::vector invocation_args = {"/usr/bin/xcrun", tool_name}; std::vector processed_args = {}; @@ -416,7 +465,8 @@ int main(int argc, char *argv[]) { std::string arg(argv[i]); ProcessArgument(arg, developer_dir, sdk_root, cwd, relative_ast_path, - linked_binary, dsym_path, toolchain_path, consumer); + linked_binary, dsym_path, original_indexstore_path, + global_indexstore_path, output_file_path, toolchain_path, consumer); } // Special mode that only prints the command. Used for testing. @@ -430,6 +480,7 @@ int main(int argc, char *argv[]) { auto response_file = WriteResponseFile(processed_args); invocation_args.push_back("@" + response_file->GetPath()); + bool copy_indexstore = use_global_indexstore; // Check to see if we should postprocess with dsymutil. bool postprocess = false; if ((!linked_binary.empty()) || (!dsym_path.empty())) { @@ -453,11 +504,25 @@ int main(int argc, char *argv[]) { return 1; } - if (!postprocess) { + if (!postprocess && !copy_indexstore) { return 0; } - std::vector dsymutil_args = {"/usr/bin/xcrun", + if (copy_indexstore) { + auto file_prefix_map = "--file-prefix-map=" + cwd + "=."; + std::vector index_import_args = {index_import_path, + file_prefix_map, + "-import-output-file", + output_file_path, + global_indexstore_path, + original_indexstore_path}; + if (!RunSubProcess(index_import_args)) { + return 1; + } + } + + if (postprocess) { + std::vector dsymutil_args = {"/usr/bin/xcrun", "dsymutil", linked_binary, "-o", diff --git a/lib/repositories.bzl b/lib/repositories.bzl index cad0083..6993ced 100644 --- a/lib/repositories.bzl +++ b/lib/repositories.bzl @@ -56,4 +56,20 @@ def apple_support_dependencies(): sha256 = "3a561c99e7bdbe9173aa653fd579fe849f1d8d67395780ab4770b1f381431d51", ) + _maybe( + http_archive, + name = "build_bazel_apple_support_index_import", + build_file_content = """ +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") +package(default_visibility = ["//visibility:public"]) +native_binary( + name = "index_import", + src = "index-import", + out = "index-import", +) +""", + urls = ["https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz"], + sha256 = "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15", + ) + apple_cc_configure()