| # Copyright 2024 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. |
| """ |
| The cc_common.link function. |
| |
| Used for C++ transitive linking. |
| """ |
| |
| load(":common/cc/compile/cc_compilation_outputs.bzl", "EMPTY_COMPILATION_OUTPUTS") |
| load(":common/cc/link/cc_linking_helper.bzl", "create_cc_link_actions") |
| load(":common/cc/link/target_types.bzl", "LINKING_MODE", "LINK_TARGET_TYPE") |
| |
| cc_internal = _builtins.internal.cc_internal |
| |
| # Translation table from language and output type to static and dynamic target type. |
| _TARGET_TYPE = { |
| ("cpp", "executable"): (None, LINK_TARGET_TYPE.EXECUTABLE), |
| ("cpp", "dynamic_library"): (None, LINK_TARGET_TYPE.DYNAMIC_LIBRARY), |
| ("objc", "executable"): (None, LINK_TARGET_TYPE.OBJC_EXECUTABLE), |
| ("objcpp", "executable"): (None, LINK_TARGET_TYPE.OBJC_EXECUTABLE), |
| ("objc", "archive"): (LINK_TARGET_TYPE.OBJC_FULLY_LINKED_ARCHIVE, None), |
| } |
| |
| # LINT.IfChange |
| |
| # IMPORTANT: This function is public API exposed on cc_common module! |
| def link( |
| *, |
| actions, |
| name, |
| feature_configuration, |
| cc_toolchain, |
| language = "c++", |
| output_type = "executable", |
| link_deps_statically = True, |
| compilation_outputs = EMPTY_COMPILATION_OUTPUTS, |
| linking_contexts = [], |
| user_link_flags = [], |
| stamp = 0, |
| additional_inputs = [], |
| additional_outputs = [], |
| variables_extension = {}, |
| # Private: |
| use_test_only_flags = False, |
| never_link = False, |
| test_only_target = False, |
| native_deps = False, |
| whole_archive = False, |
| additional_linkstamp_defines = [], |
| always_link = False, |
| link_artifact_name_suffix = "", |
| main_output = None, |
| use_shareable_artifact_factory = False, |
| build_config = None, |
| emit_interface_shared_library = False): |
| """Used for C++ transitive linking. |
| |
| In the most basic and most used case, the function creates an action for a single executable or |
| a dynamic library (`output_type`) for `language`, called `name`, linking all transitive |
| libraries using the `feature_configuration` (describing current target or package feature |
| configuration) and `cc_toolchain`. |
| |
| The linking mode can be either static (`link_deps_statically` == True) or dynamic. |
| |
| It links the current target's `compilation_outputs` with `linking_contexts` from target's |
| dependencies. Using custom `user_link_flags` and `stamp`-ing. |
| |
| Callee may specify `additional_inputs` and `additional_outputs` to C++ linking action, and |
| custom `variables_extension`, which are passed to link command line. |
| |
| When ThinLTO is enabled a second LTO indexing action is created. |
| |
| TODO(b/338618120): during Starlarkification of rules several private parameters were introduced, |
| those parameters need to be eventually removed or made public. |
| The booleans control various bits and pieces of the linking or LTO indexing action. |
| |
| TODO(b/338618120): `main_output`, `use_shareable_artifact_factory` and `build_config` are |
| partners in crime, making it possible for Java, Apple and Android rules to link artifacts under |
| different configurations - that's used for building dependencies for different platforms. |
| |
| Special case is Objc's archive, which doesn't do transitive linking at all. |
| TODO(b/338618120): Migrate Objc to cc_common.create_linking_context_from_compilation_outputs. |
| |
| Args: |
| actions: (Actions) `actions` object. |
| name: (str) This is used for naming the output artifacts of actions created by this method. |
| feature_configuration: (FeatureConfiguration) `feature_configuration` to be queried. |
| cc_toolchain: (CcToolchainInfo) CcToolchainInfo provider to be used. |
| language: ("cpp"|"objc") Only C++ supported for now. Do not use this parameter. |
| output_type: ("executable"|"dynamic_library"|"archive") Can be either 'executable' or 'dynamic_library'. |
| link_deps_statically: (bool) True to link dependencies statically, False dynamically. |
| compilation_outputs: (CompilationOutputs) Compilation outputs containing object files to link. |
| linking_contexts: (list[LinkingContext]) Linking contexts from dependencies to be linked |
| into the linking context generated by this rule. |
| user_link_flags: (list[str]) Additional list of linker options. |
| stamp: (-1|0|1): Whether to include build information in the linked executable, if output_type is |
| 'executable'. If 1, build information is always included. If 0 (the |
| default build information is always excluded. If -1, uses the default |
| behavior, which may be overridden by the --[no]stamp flag. This should be |
| unset (or set to 0) when generating the executable output for test rules. |
| additional_inputs: (list[File]|depset[File]) For additional inputs to the linking action, |
| e.g.: linking scripts. |
| additional_outputs: (list[File]) For additional outputs to the linking action, e.g.: map files. |
| variables_extension: (dict[str, str|list[str]|depset[str]]) Additional variables to pass to |
| the toolchain configuration when creating link command line. |
| use_test_only_flags: (bool) undocumented. |
| never_link: (bool) undocumented. |
| test_only_target: (bool) undocumented. |
| native_deps: (bool) undocumented. |
| whole_archive: (bool) undocumented. |
| additional_linkstamp_defines: (list[str]) undocumented. |
| always_link: (bool) undocumented. |
| link_artifact_name_suffix: (str) undocumented. |
| main_output: (File) Name of the main output artifact that will be produced by the linker. |
| Only set this if the default name generation does not match you needs |
| For output_type=executable, this is the final executable filename. |
| For output_type=dynamic_library, this is the shared library filename. |
| If not specified, then one will be computed based on `name` and `output_type`. |
| use_shareable_artifact_factory: (bool) undocumented. |
| build_config: (None|BuildConfiguration) undocumented. |
| emit_interface_shared_library: (bool) When 'output_type' is 'dynamic_library' and this |
| parameter is set to True, an interface shared library will be generated during |
| linking. On Windows the interface shared library will always be generated |
| regardless of this parameter since it is a requirement for linking. |
| Returns: |
| (CcLinkingOutputs = { |
| library_to_link: LibraryToLink, |
| all_lto_artifacts: list[LtoBackendArtifacts], |
| executable: None|File |
| }) |
| """ |
| # LINT.ThenChange(//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/cpp/CcModuleApi.java) |
| |
| # TODO(bazel-team): Rename always_link to alwayslink before delisting. Also it looks like the |
| # suffix parameter can be removed since we can use `name` for the same thing. |
| if output_type not in ["executable", "dynamic_library", "archive"]: |
| fail("Output type '%s' is not supported" % output_type) |
| language = language.replace("++", "pp") |
| if language not in ["cpp", "objc", "objcpp"]: |
| fail("Language '%s' is not supported" % language) |
| if (language, output_type) not in _TARGET_TYPE: |
| fail("Language '%s' does not support %s" % (language, output_type)) |
| |
| static_link_type, dynamic_link_type = _TARGET_TYPE[(language, output_type)] |
| |
| if type(additional_inputs) == type([]): |
| additional_inputs = depset(additional_inputs) |
| |
| if static_link_type == LINK_TARGET_TYPE.STATIC_LIBRARY and always_link: |
| static_link_type = LINK_TARGET_TYPE.ALWAYS_LINK_STATIC_LIBRARY |
| |
| linking_mode = LINKING_MODE.STATIC if link_deps_statically else LINKING_MODE.DYNAMIC |
| |
| # TODO(b/338618120): Migrate Apple and Android rules, so they don't need to use build_config |
| # when calling link. This happens because they are using deps with split configuration |
| actions = cc_internal.wrap_link_actions(actions, build_config, use_shareable_artifact_factory) |
| |
| return create_cc_link_actions( |
| actions, |
| name, |
| static_link_type, |
| dynamic_link_type, |
| linking_mode, |
| feature_configuration, |
| cc_toolchain, |
| compilation_outputs, |
| linking_contexts, |
| user_link_flags, # linkopts |
| stamp, |
| additional_inputs, |
| additional_outputs, # linker_outputs |
| variables_extension, |
| use_test_only_flags, |
| never_link, # neverlink |
| test_only_target, |
| whole_archive, |
| native_deps, |
| additional_linkstamp_defines, |
| # alwayslink may be deprecated but we're trying to replicate CcBinary as closely as possible for the moment. |
| # TODO(b/331164666): remove alwayslink, the information is in static_link_type already |
| always_link, |
| link_artifact_name_suffix, |
| main_output, # linker_output_artifact |
| emit_interface_shared_libraries = dynamic_link_type == LINK_TARGET_TYPE.DYNAMIC_LIBRARY and |
| (emit_interface_shared_library or |
| feature_configuration.is_enabled("targets_windows")), |
| ) |