load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "CPP_COMPILE_ACTION_NAME") def _pch_impl(ctx): deps_cc_info = cc_common.merge_cc_infos( cc_infos = [dep[CcInfo] for dep in ctx.attr.deps], ) if not ctx.attr.enabled: return [deps_cc_info] cc_toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo] feature_configuration = cc_common.configure_features( ctx = ctx, cc_toolchain = cc_toolchain, requested_features = ctx.features, unsupported_features = ctx.disabled_features, ) cc_compiler_path = cc_common.get_tool_for_action( feature_configuration = feature_configuration, action_name = CPP_COMPILE_ACTION_NAME, ) generated_header_file = ctx.actions.declare_file(ctx.label.name + ".h") ctx.actions.write( generated_header_file, "\n".join(["#include \"{}\"".format(include) for include in ctx.attr.includes]) + "\n", ) pch_flags = ["-x", "c++-header"] if "clang" in cc_compiler_path: pch_flags += ["-Xclang", "-fno-pch-timestamp"] if "gcc" in cc_compiler_path: pch_flags.append("-fpch-preprocess") pch_file = ctx.actions.declare_file(ctx.label.name + ".pch") deps_ctx = deps_cc_info.compilation_context cc_compile_variables = cc_common.create_compile_variables( feature_configuration = feature_configuration, cc_toolchain = cc_toolchain, user_compile_flags = ctx.fragments.cpp.copts + ctx.fragments.cpp.cxxopts + pch_flags, source_file = generated_header_file.path, output_file = pch_file.path, preprocessor_defines = depset(deps_ctx.defines.to_list() + deps_ctx.local_defines.to_list()), include_directories = deps_ctx.includes, quote_include_directories = deps_ctx.quote_includes, system_include_directories = deps_ctx.system_includes, framework_include_directories = deps_ctx.framework_includes, ) env = cc_common.get_environment_variables( feature_configuration = feature_configuration, action_name = CPP_COMPILE_ACTION_NAME, variables = cc_compile_variables, ) command_line = cc_common.get_memory_inefficient_command_line( feature_configuration = feature_configuration, action_name = CPP_COMPILE_ACTION_NAME, variables = cc_compile_variables, ) transitive_headers = [] for dep in ctx.attr.deps: transitive_headers.append(dep[CcInfo].compilation_context.headers) ctx.actions.run( executable = cc_compiler_path, arguments = command_line, env = env, inputs = depset( direct = [generated_header_file], transitive = [cc_toolchain.all_files] + transitive_headers, ), outputs = [pch_file], ) return [ DefaultInfo(files = depset(direct = [pch_file])), cc_common.merge_cc_infos( direct_cc_infos = [ CcInfo( compilation_context = cc_common.create_compilation_context( headers = depset([pch_file, generated_header_file]), ), ), ], cc_infos = [deps_cc_info], ), ] _pch = rule( attrs = dict( includes = attr.string_list( mandatory = True, allow_empty = False, ), deps = attr.label_list( mandatory = True, allow_empty = False, providers = [CcInfo], ), enabled = attr.bool( mandatory = True, ), _cc_toolchain = attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), ), fragments = ["cpp"], provides = [CcInfo], toolchains = ["@bazel_tools//tools/cpp:toolchain_type"], implementation = _pch_impl, ) def pch(name, includes, deps): native.cc_library( name = name + "_libs", visibility = ["//visibility:private"], deps = deps, alwayslink = 1, ) _pch( name = name, deps = [name + "_libs"], includes = includes, # visibility = visibility, tags = ["no-remote"], enabled = True, )