| # Copyright 2020 The Bazel Authors. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """cc_library Starlark implementation replacing native""" | |
| load("//cc:find_cc_toolchain.bzl", "find_cc_toolchain") | |
| load("//cc/common:cc_common.bzl", "cc_common") | |
| load("//cc/common:cc_helper.bzl", "cc_helper") | |
| load("//cc/common:cc_info.bzl", "CcInfo") | |
| load("//cc/common:semantics.bzl", "semantics") | |
| load(":function_providing_rule.bzl", "wrap_starlark_function") | |
| def _cc_library_impl(ctx): | |
| semantics.validate(ctx, "cc_library") | |
| cc_helper.check_srcs_extensions(ctx, ALLOWED_SRC_FILES, "cc_library", True) | |
| semantics.check_cc_shared_library_tags(ctx) | |
| cc_toolchain = find_cc_toolchain(ctx) | |
| cc_helper.report_invalid_options(cc_toolchain, ctx.fragments.cpp) | |
| features = ctx.features | |
| feature_configuration = cc_common.configure_features( | |
| ctx = ctx, | |
| cc_toolchain = cc_toolchain, | |
| requested_features = features, | |
| unsupported_features = ctx.disabled_features, | |
| ) | |
| cc_helper.check_cpp_modules(ctx, feature_configuration) | |
| precompiled_files = cc_helper.build_precompiled_files(ctx = ctx) | |
| semantics.validate_attributes(ctx) | |
| _check_no_repeated_srcs(ctx) | |
| semantics.check_can_use_implementation_deps(ctx) | |
| interface_deps = ctx.attr.deps + cc_helper.get_cc_runtimes(ctx, True) | |
| runtimes_copts = cc_helper.get_cc_runtimes_copts(ctx) | |
| compilation_contexts = cc_helper.get_compilation_contexts_from_deps(interface_deps) | |
| implementation_compilation_contexts = cc_helper.get_compilation_contexts_from_deps(ctx.attr.implementation_deps) | |
| additional_make_variable_substitutions = cc_helper.get_toolchain_global_make_variables(cc_toolchain, feature_configuration) | |
| additional_make_variable_substitutions.update(cc_helper.get_cc_flags_make_variable(ctx, feature_configuration, cc_toolchain)) | |
| (compilation_context, srcs_compilation_outputs) = cc_common.compile( | |
| actions = ctx.actions, | |
| name = ctx.label.name, | |
| cc_toolchain = cc_toolchain, | |
| feature_configuration = feature_configuration, | |
| user_compile_flags = runtimes_copts + cc_helper.get_copts(ctx, feature_configuration, additional_make_variable_substitutions, attr = "copts", requested_features = features), | |
| conly_flags = cc_helper.get_copts(ctx, feature_configuration, additional_make_variable_substitutions, attr = "conlyopts", requested_features = features), | |
| cxx_flags = cc_helper.get_copts(ctx, feature_configuration, additional_make_variable_substitutions, attr = "cxxopts", requested_features = features), | |
| defines = cc_helper.defines(ctx, additional_make_variable_substitutions), | |
| local_defines = cc_helper.local_defines(ctx, additional_make_variable_substitutions) + cc_helper.get_local_defines_for_runfiles_lookup(ctx, ctx.attr.deps + ctx.attr.implementation_deps), | |
| includes = cc_helper.include_dirs(ctx, additional_make_variable_substitutions), | |
| local_includes = cc_helper.include_dirs(ctx, additional_make_variable_substitutions, attr = "local_includes"), | |
| purpose = "cc_library-compile", | |
| srcs = cc_helper.get_srcs(ctx), | |
| module_interfaces = cc_helper.get_cpp_module_interfaces(ctx), | |
| private_hdrs = cc_helper.get_private_hdrs(ctx), | |
| public_hdrs = cc_helper.get_public_hdrs(ctx), | |
| code_coverage_enabled = cc_helper.is_code_coverage_enabled(ctx), | |
| compilation_contexts = compilation_contexts, | |
| implementation_compilation_contexts = implementation_compilation_contexts, | |
| textual_hdrs = ctx.files.textual_hdrs, | |
| include_prefix = ctx.attr.include_prefix, | |
| strip_include_prefix = ctx.attr.strip_include_prefix, | |
| additional_inputs = ctx.files.additional_compiler_inputs, | |
| ) | |
| precompiled_objects = cc_common.create_compilation_outputs( | |
| objects = depset(precompiled_files[0]), | |
| pic_objects = depset(precompiled_files[1]), | |
| ) | |
| compilation_outputs = cc_common.merge_compilation_outputs( | |
| compilation_outputs = [precompiled_objects, srcs_compilation_outputs], | |
| ) | |
| supports_dynamic_linker = cc_common.is_enabled( | |
| feature_configuration = feature_configuration, | |
| feature_name = "supports_dynamic_linker", | |
| ) | |
| create_dynamic_library = (not ctx.attr.linkstatic and | |
| supports_dynamic_linker and | |
| (not cc_helper.is_compilation_outputs_empty(compilation_outputs) or | |
| cc_common.is_enabled( | |
| feature_configuration = feature_configuration, | |
| feature_name = "header_module_codegen", | |
| ))) | |
| output_group_builder = {} | |
| has_compilation_outputs = not cc_helper.is_compilation_outputs_empty(compilation_outputs) | |
| linking_context = CcInfo().linking_context | |
| empty_archive_linking_context = CcInfo().linking_context | |
| linking_contexts = cc_helper.get_linking_contexts_from_deps(ctx.attr.deps) | |
| linking_contexts.extend( | |
| cc_helper.get_linking_contexts_from_deps( | |
| ctx.attr.implementation_deps + cc_helper.get_cc_runtimes(ctx, True), | |
| ), | |
| ) | |
| if ctx.file.linkstamp != None: | |
| linkstamps = [] | |
| linkstamps.append(cc_common.create_linkstamp( | |
| linkstamp = ctx.file.linkstamp, | |
| headers = compilation_context.headers, | |
| )) | |
| linkstamps_linker_input = cc_common.create_linker_input( | |
| owner = ctx.label, | |
| linkstamps = depset(linkstamps), | |
| ) | |
| linkstamps_linking_context = cc_common.create_linking_context( | |
| linker_inputs = depset([linkstamps_linker_input]), | |
| ) | |
| linking_contexts.append(linkstamps_linking_context) | |
| if has_compilation_outputs: | |
| dll_name_suffix = "" | |
| additional_inputs = _filter_linker_scripts(ctx.files.deps) + ctx.files.additional_linker_inputs | |
| link_variables = {} | |
| is_windows_enabled = cc_common.is_enabled(feature_configuration = feature_configuration, feature_name = "targets_windows") | |
| if is_windows_enabled: | |
| dll_name_suffix = cc_helper.dll_hash_suffix(ctx, feature_configuration, ctx.fragments.cpp) | |
| generated_def_file = None | |
| generated_def_file = cc_helper.generate_def_file( | |
| ctx, | |
| ctx.file._def_parser, | |
| compilation_outputs.objects, | |
| ctx.label.name + dll_name_suffix, | |
| cc_toolchain, | |
| feature_configuration, | |
| ) | |
| if generated_def_file != None: | |
| output_group_builder["def_file"] = depset([generated_def_file]) | |
| win_def_file = cc_helper.get_windows_def_file_for_linking(ctx, ctx.file.win_def_file, generated_def_file, feature_configuration) | |
| link_variables["def_file_path"] = win_def_file.path | |
| additional_inputs.append(win_def_file) | |
| ( | |
| linking_context, | |
| linking_outputs, | |
| ) = cc_common.create_linking_context_from_compilation_outputs( | |
| actions = ctx.actions, | |
| name = ctx.label.name, | |
| compilation_outputs = compilation_outputs, | |
| cc_toolchain = cc_toolchain, | |
| feature_configuration = feature_configuration, | |
| additional_inputs = additional_inputs, | |
| linking_contexts = linking_contexts, | |
| user_link_flags = cc_helper.linkopts(ctx, additional_make_variable_substitutions, cc_toolchain), | |
| alwayslink = ctx.attr.alwayslink, | |
| disallow_dynamic_library = not create_dynamic_library, | |
| linked_dll_name_suffix = dll_name_suffix, | |
| variables_extension = link_variables, | |
| ) | |
| else: | |
| linking_outputs = struct(library_to_link = None) | |
| _add_linker_artifacts_output_groups(output_group_builder, linking_outputs) | |
| precompiled_libraries = _convert_precompiled_libraries_to_library_to_link( | |
| ctx, | |
| cc_toolchain, | |
| feature_configuration, | |
| ctx.fragments.cpp.force_pic(), | |
| precompiled_files, | |
| ctx.attr.alwayslink, | |
| ) | |
| if not cc_helper.is_compilation_outputs_empty(compilation_outputs): | |
| _check_if_link_outputs_colliding_with_precompiled_files( | |
| ctx, | |
| linking_outputs, | |
| precompiled_libraries, | |
| ) | |
| precompiled_linking_context = cc_helper.build_linking_context_from_libraries(ctx, precompiled_libraries) | |
| contexts_to_merge = [precompiled_linking_context, empty_archive_linking_context] | |
| if has_compilation_outputs: | |
| contexts_to_merge.append(linking_context) | |
| else: | |
| user_link_flags = cc_helper.linkopts(ctx, additional_make_variable_substitutions, cc_toolchain) | |
| linker_scripts = _filter_linker_scripts(ctx.files.deps) | |
| additional_linker_inputs = ctx.files.additional_linker_inputs | |
| linker_input = cc_common.create_linker_input( | |
| owner = ctx.label, | |
| user_link_flags = user_link_flags, | |
| additional_inputs = depset(linker_scripts + additional_linker_inputs), | |
| ) | |
| contexts_to_merge.append(cc_common.create_linking_context(linker_inputs = depset([linker_input]))) | |
| contexts_to_merge.extend(linking_contexts) | |
| linking_context = cc_common.merge_linking_contexts( | |
| linking_contexts = contexts_to_merge, | |
| ) | |
| libraries_to_link = _create_libraries_to_link_list( | |
| linking_outputs.library_to_link, | |
| precompiled_libraries, | |
| ) | |
| linking_context_for_runfiles = cc_helper.build_linking_context_from_libraries(ctx, libraries_to_link) | |
| cc_native_library_info = cc_helper.collect_native_cc_libraries( | |
| deps = ctx.attr.deps, | |
| libraries = libraries_to_link, | |
| ) | |
| files_builder = [] | |
| if linking_outputs.library_to_link != None: | |
| artifacts_to_build = linking_outputs.library_to_link | |
| if artifacts_to_build.static_library != None: | |
| files_builder.append(artifacts_to_build.static_library) | |
| if artifacts_to_build.pic_static_library != None: | |
| files_builder.append(artifacts_to_build.pic_static_library) | |
| if not cc_common.is_enabled( | |
| feature_configuration = feature_configuration, | |
| feature_name = "targets_windows", | |
| ): | |
| if artifacts_to_build.resolved_symlink_dynamic_library != None: | |
| files_builder.append(artifacts_to_build.resolved_symlink_dynamic_library) | |
| elif artifacts_to_build.dynamic_library != None: | |
| files_builder.append(artifacts_to_build.dynamic_library) | |
| if artifacts_to_build.resolved_symlink_interface_library != None: | |
| files_builder.append(artifacts_to_build.resolved_symlink_interface_library) | |
| elif artifacts_to_build.interface_library != None: | |
| files_builder.append(artifacts_to_build.interface_library) | |
| if hasattr(compilation_outputs, "gcno_files"): | |
| gcno_files = compilation_outputs.gcno_files() | |
| else: | |
| gcno_files = compilation_outputs._gcno_files | |
| if hasattr(compilation_outputs, "pic_gcno_files"): | |
| pic_gcno_files = compilation_outputs.pic_gcno_files() | |
| else: | |
| pic_gcno_files = compilation_outputs._pic_gcno_files | |
| instrumented_files_info = cc_helper.create_cc_instrumented_files_info( | |
| ctx = ctx, | |
| cc_config = ctx.fragments.cpp, | |
| cc_toolchain = cc_toolchain, | |
| feature_configuration = feature_configuration, | |
| metadata_files = gcno_files + pic_gcno_files, | |
| ) | |
| runfiles_list = [] | |
| for data_dep in ctx.attr.data: | |
| if data_dep[DefaultInfo].data_runfiles.files: | |
| runfiles_list.append(data_dep[DefaultInfo].data_runfiles) | |
| else: | |
| # This branch ensures interop with custom Starlark rules following | |
| # https://bazel.build/extending/rules#runfiles_features_to_avoid | |
| runfiles_list.append(ctx.runfiles(transitive_files = data_dep[DefaultInfo].files)) | |
| runfiles_list.append(data_dep[DefaultInfo].default_runfiles) | |
| for src in ctx.attr.srcs: | |
| runfiles_list.append(src[DefaultInfo].default_runfiles) | |
| for dep in ctx.attr.deps: | |
| runfiles_list.append(dep[DefaultInfo].default_runfiles) | |
| for dep in ctx.attr.implementation_deps: | |
| runfiles_list.append(dep[DefaultInfo].default_runfiles) | |
| runfiles = ctx.runfiles().merge_all(runfiles_list) | |
| default_runfiles = ctx.runfiles(files = cc_helper.get_dynamic_libraries_for_runtime(linking_context_for_runfiles, True)) | |
| default_runfiles = runfiles.merge(default_runfiles) | |
| data_runfiles = ctx.runfiles(files = cc_helper.get_dynamic_libraries_for_runtime(linking_context_for_runfiles, False)) | |
| data_runfiles = runfiles.merge(data_runfiles) | |
| current_output_groups = cc_helper.build_output_groups_for_emitting_compile_providers( | |
| compilation_outputs, | |
| compilation_context, | |
| ctx.fragments.cpp, | |
| cc_toolchain, | |
| feature_configuration, | |
| ctx, | |
| generate_hidden_top_level_group = True, | |
| ) | |
| providers = [] | |
| providers.append(DefaultInfo( | |
| files = depset(files_builder), | |
| default_runfiles = default_runfiles, | |
| data_runfiles = data_runfiles, | |
| )) | |
| debug_context = cc_helper.merge_cc_debug_contexts( | |
| compilation_outputs, | |
| cc_helper.get_providers(ctx.attr.deps + ctx.attr.implementation_deps, CcInfo), | |
| ) | |
| cc_info = CcInfo( | |
| compilation_context = compilation_context, | |
| linking_context = linking_context, | |
| debug_context = debug_context, | |
| cc_native_library_info = cc_native_library_info, | |
| ) | |
| merged_output_groups = cc_helper.merge_output_groups( | |
| [current_output_groups, output_group_builder], | |
| ) | |
| providers.append(cc_info) | |
| providers.append(OutputGroupInfo(**merged_output_groups)) | |
| providers.append(instrumented_files_info) | |
| return providers | |
| def _add_linker_artifacts_output_groups(output_group_builder, linking_outputs): | |
| archive_file = [] | |
| dynamic_library = [] | |
| lib = linking_outputs.library_to_link | |
| if lib == None: | |
| return | |
| if lib.static_library != None: | |
| archive_file.append(lib.static_library) | |
| elif lib.pic_static_library != None: | |
| archive_file.append(lib.pic_static_library) | |
| if lib.resolved_symlink_dynamic_library != None: | |
| dynamic_library.append(lib.resolved_symlink_dynamic_library) | |
| elif lib.dynamic_library != None: | |
| dynamic_library.append(lib.dynamic_library) | |
| if lib.resolved_symlink_interface_library != None: | |
| dynamic_library.append(lib.resolved_symlink_interface_library) | |
| elif lib.interface_library != None: | |
| dynamic_library.append(lib.interface_library) | |
| output_group_builder["archive"] = depset(archive_file) | |
| output_group_builder["dynamic_library"] = depset(dynamic_library) | |
| def _convert_precompiled_libraries_to_library_to_link( | |
| ctx, | |
| cc_toolchain, | |
| feature_configuration, | |
| force_pic, | |
| precompiled_files, | |
| alwayslink): | |
| static_libraries = _build_map_identifier_to_artifact(precompiled_files[2]) | |
| pic_static_libraries = _build_map_identifier_to_artifact(precompiled_files[3]) | |
| alwayslink_static_libraries = _build_map_identifier_to_artifact(precompiled_files[4]) | |
| alwayslink_pic_static_libraries = _build_map_identifier_to_artifact(precompiled_files[5]) | |
| dynamic_libraries = _build_map_identifier_to_artifact(precompiled_files[6]) | |
| libraries = [] | |
| identifiers_used = {} | |
| static_libraries_it = [] | |
| static_libraries_it.extend(static_libraries.items()) | |
| static_libraries_it.extend(alwayslink_static_libraries.items()) | |
| for identifier, v in static_libraries_it: | |
| static_library = None | |
| pic_static_library = None | |
| dynamic_library = None | |
| has_pic = identifier in pic_static_libraries | |
| has_always_pic = identifier in alwayslink_pic_static_libraries | |
| if has_pic or has_always_pic: | |
| if has_pic: | |
| pic_static_library = pic_static_libraries[identifier] | |
| else: | |
| pic_static_library = alwayslink_pic_static_libraries[identifier] | |
| if not force_pic or not (has_pic or has_always_pic): | |
| static_library = v | |
| if identifier in dynamic_libraries: | |
| dynamic_library = dynamic_libraries[identifier] | |
| identifiers_used[identifier] = True | |
| library = cc_common.create_library_to_link( | |
| actions = ctx.actions, | |
| feature_configuration = feature_configuration, | |
| cc_toolchain = cc_toolchain, | |
| static_library = static_library, | |
| pic_static_library = pic_static_library, | |
| dynamic_library = dynamic_library, | |
| alwayslink = alwayslink or identifier in alwayslink_static_libraries, | |
| ) | |
| libraries.append(library) | |
| pic_static_libraries_it = [] | |
| pic_static_libraries_it.extend(pic_static_libraries.items()) | |
| pic_static_libraries_it.extend(alwayslink_pic_static_libraries.items()) | |
| for identifier, v in pic_static_libraries_it: | |
| if identifier in identifiers_used: | |
| continue | |
| pic_static_library = v | |
| if identifier in dynamic_libraries: | |
| dynamic_library = dynamic_libraries[identifier] | |
| identifiers_used[identifier] = True | |
| library = cc_common.create_library_to_link( | |
| actions = ctx.actions, | |
| feature_configuration = feature_configuration, | |
| cc_toolchain = cc_toolchain, | |
| pic_static_library = pic_static_library, | |
| alwayslink = alwayslink or identifier in alwayslink_static_libraries, | |
| ) | |
| libraries.append(library) | |
| for identifier, v in dynamic_libraries.items(): | |
| if identifier in identifiers_used: | |
| continue | |
| dynamic_library = dynamic_libraries[identifier] | |
| library = cc_common.create_library_to_link( | |
| actions = ctx.actions, | |
| feature_configuration = feature_configuration, | |
| cc_toolchain = cc_toolchain, | |
| dynamic_library = dynamic_library, | |
| ) | |
| libraries.append(library) | |
| return libraries | |
| def _build_map_identifier_to_artifact(artifacts): | |
| libraries = {} | |
| for artifact in artifacts: | |
| identifier = _identifier_of_artifact(artifact) | |
| if identifier in libraries: | |
| fail( | |
| "Trying to link twice a library with the same identifier '{}',".format(identifier) + | |
| "files: {} and {}".format( | |
| artifact.short_path, | |
| libraries[identifier].short_path, | |
| ), | |
| attr = "srcs", | |
| ) | |
| libraries[identifier] = artifact | |
| return libraries | |
| _ARTIFACT_IDENTIFIER_COMPOUND_SUFFIXES = (".pic.a", ".nopic.a", ".pic.lo") | |
| def _identifier_of_artifact(artifact): | |
| name = artifact.short_path | |
| if name.endswith(_ARTIFACT_IDENTIFIER_COMPOUND_SUFFIXES): | |
| return name.rsplit(".", 2)[0] | |
| return name[:len(name) - len(artifact.extension) - 1] | |
| def _identifier_of_library(library): | |
| if library.static_library != None: | |
| return _identifier_of_artifact(library.static_library) | |
| if library.pic_static_library != None: | |
| return _identifier_of_artifact(library.pic_static_library) | |
| if library.dynamic_library != None: | |
| return _identifier_of_artifact(library.dynamic_library) | |
| if library.interface_library != None: | |
| return _identifier_of_artifact(library.interface_library) | |
| return None | |
| def _create_libraries_to_link_list(current_library, precompiled_libraries): | |
| libraries = [] | |
| libraries.extend(precompiled_libraries) | |
| if current_library != None: | |
| libraries.append(current_library) | |
| return libraries | |
| def _filter_linker_scripts(files): | |
| linker_scripts = [] | |
| for file in files: | |
| extension = "." + file.extension | |
| if extension in LINKER_SCRIPT: | |
| linker_scripts.append(file) | |
| return linker_scripts | |
| def _check_if_link_outputs_colliding_with_precompiled_files(ctx, linking_outputs, precompiled_libraries): | |
| identifier = _identifier_of_library(linking_outputs.library_to_link) | |
| for precompiled_library in precompiled_libraries: | |
| precompiled_library_identifier = _identifier_of_library(precompiled_library) | |
| if precompiled_library_identifier == identifier: | |
| fail("Can't put library with identifier '{}' into the srcs of a cc_library with".format(identifier) + | |
| " the same name ({}) which also contains other code or objects to link".format( | |
| ctx.label.name, | |
| )) | |
| def _check_no_repeated_srcs(ctx): | |
| seen = {} | |
| for target in ctx.attr.srcs: | |
| if DefaultInfo in target: | |
| for file in target[DefaultInfo].files.to_list(): | |
| extension = "." + file.extension | |
| if extension not in cc_helper.extensions.CC_HEADER: | |
| if extension in cc_helper.extensions.CC_AND_OBJC: | |
| if file.path in seen: | |
| if seen[file.path] != target.label: | |
| fail("Artifact '{}' is duplicated (through ".format(file.path) + | |
| "'{}' and '{}')".format(str(seen[file.path]), str(target.label))) | |
| seen[file.path] = target.label | |
| ALLOWED_SRC_FILES = [] | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.CC_SOURCE) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.C_SOURCE) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.CC_HEADER) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.ASSEMBLER_WITH_C_PREPROCESSOR) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.ASSEMBLER) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.ARCHIVE) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.PIC_ARCHIVE) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.ALWAYSLINK_LIBRARY) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.ALWAYSLINK_PIC_LIBRARY) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.SHARED_LIBRARY) | |
| SRCS_FOR_COMPILATION = [] | |
| SRCS_FOR_COMPILATION.extend(cc_helper.extensions.CC_SOURCE) | |
| SRCS_FOR_COMPILATION.extend(cc_helper.extensions.C_SOURCE) | |
| SRCS_FOR_COMPILATION.extend(cc_helper.extensions.ASSEMBLER_WITH_C_PREPROCESSOR) | |
| SRCS_FOR_COMPILATION.extend(cc_helper.extensions.ASSEMBLER) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.OBJECT_FILE) | |
| ALLOWED_SRC_FILES.extend(cc_helper.extensions.PIC_OBJECT_FILE) | |
| LINKER_SCRIPT = [".ld", ".lds", ".ldscript"] | |
| cc_library_impl = _cc_library_impl | |
| cc_library_impl_wrapper = wrap_starlark_function(_cc_library_impl) |