| package com.google.devtools.build.lib.rules.cpp; |
| // Copyright 2018 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. |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.collect.nestedset.Depset; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; |
| import com.google.devtools.build.lib.skylarkbuildapi.cpp.LibraryToLinkApi; |
| import com.google.devtools.build.lib.syntax.Printer; |
| import com.google.devtools.build.lib.syntax.Sequence; |
| import com.google.devtools.build.lib.syntax.StarlarkList; |
| import java.util.List; |
| import javax.annotation.Nullable; |
| |
| /** |
| * Encapsulates information for linking a library. |
| * |
| * <p>TODO(b/118663806): This class which shall be renamed later to LibraryToLink (once the old |
| * LibraryToLink implementation is removed) will have all the information necessary for linking a |
| * library in all of its variants : static params for executable, static params for dynamic library, |
| * dynamic params for executable and dynamic params for dynamic library. |
| */ |
| @AutoValue |
| @Immutable |
| public abstract class LibraryToLink implements LibraryToLinkApi<Artifact> { |
| |
| @Override |
| public boolean isImmutable() { |
| return true; // immutable and Starlark-hashable |
| } |
| |
| public static final Depset.ElementType TYPE = Depset.ElementType.of(LibraryToLink.class); |
| |
| public Artifact getDynamicLibraryForRuntimeOrNull(boolean linkingStatically) { |
| if (getDynamicLibrary() == null) { |
| return null; |
| } |
| if (linkingStatically && (getStaticLibrary() != null || getPicStaticLibrary() != null)) { |
| return null; |
| } |
| return getDynamicLibrary(); |
| } |
| |
| private LinkerInputs.LibraryToLink picStaticLibraryToLink; |
| private LinkerInputs.LibraryToLink staticLibraryToLink; |
| private LinkerInputs.LibraryToLink dynamicLibraryToLink; |
| private LinkerInputs.LibraryToLink interfaceLibraryToLink; |
| |
| public abstract String getLibraryIdentifier(); |
| |
| @Nullable |
| @Override |
| public abstract Artifact getStaticLibrary(); |
| |
| @Nullable |
| public abstract ImmutableList<Artifact> getObjectFiles(); |
| |
| @Nullable |
| @Override |
| public Sequence<Artifact> getObjectFilesForStarlark() { |
| if (getObjectFiles() == null) { |
| return StarlarkList.empty(); |
| } |
| return StarlarkList.immutableCopyOf(getObjectFiles()); |
| } |
| |
| @Nullable |
| public abstract ImmutableMap<Artifact, LtoBackendArtifacts> getSharedNonLtoBackends(); |
| |
| @Nullable |
| public abstract LtoCompilationContext getLtoCompilationContext(); |
| |
| @Nullable |
| @Override |
| public abstract Artifact getPicStaticLibrary(); |
| |
| @Nullable |
| public abstract ImmutableList<Artifact> getPicObjectFiles(); |
| |
| @Nullable |
| @Override |
| public Sequence<Artifact> getPicObjectFilesForStarlark() { |
| if (getPicObjectFiles() == null) { |
| return StarlarkList.empty(); |
| } |
| return StarlarkList.immutableCopyOf(getPicObjectFiles()); |
| } |
| |
| @Nullable |
| public abstract ImmutableMap<Artifact, LtoBackendArtifacts> getPicSharedNonLtoBackends(); |
| |
| @Nullable |
| public abstract LtoCompilationContext getPicLtoCompilationContext(); |
| |
| @Nullable |
| @Override |
| public abstract Artifact getDynamicLibrary(); |
| |
| @Nullable |
| @Override |
| public abstract Artifact getResolvedSymlinkDynamicLibrary(); |
| |
| @Nullable |
| @Override |
| public abstract Artifact getInterfaceLibrary(); |
| |
| @Nullable |
| @Override |
| public abstract Artifact getResolvedSymlinkInterfaceLibrary(); |
| |
| @Override |
| public abstract boolean getAlwayslink(); |
| |
| // TODO(plf): This is just needed for Go, do not expose to Starlark and try to remove it. This was |
| // introduced to let a linker input declare that it needs debug info in the executable. |
| // Specifically, this was introduced for linking Go into a C++ binary when using the gccgo |
| // compiler. |
| abstract boolean getMustKeepDebug(); |
| |
| abstract boolean getDisableWholeArchive(); |
| |
| @Override |
| public void debugPrint(Printer printer) { |
| printer.append("<LibraryToLink("); |
| printer.append( |
| Joiner.on(", ") |
| .skipNulls() |
| .join( |
| mapEntry("object", getObjectFiles()), |
| mapEntry("pic_objects", getPicObjectFiles()), |
| mapEntry("static_library", getStaticLibrary()), |
| mapEntry("pic_static_library", getPicStaticLibrary()), |
| mapEntry("dynamic_library", getDynamicLibrary()), |
| mapEntry("resolved_symlink_dynamic_library", getResolvedSymlinkDynamicLibrary()), |
| mapEntry("interface_library", getInterfaceLibrary()), |
| mapEntry( |
| "resolved_symlink_interface_library", getResolvedSymlinkInterfaceLibrary()), |
| mapEntry("alwayslink", getAlwayslink()))); |
| printer.append(")>"); |
| } |
| |
| private static String mapEntry(String keyName, Object value) { |
| if (value == null) { |
| return null; |
| } else { |
| return keyName + "=" + value; |
| } |
| } |
| |
| public static Builder builder() { |
| return new AutoValue_LibraryToLink.Builder() |
| .setMustKeepDebug(false) |
| .setAlwayslink(false) |
| .setDisableWholeArchive(false); |
| } |
| |
| LinkerInputs.LibraryToLink getStaticLibraryToLink() { |
| Preconditions.checkNotNull(getStaticLibrary(), this); |
| if (staticLibraryToLink != null) { |
| return staticLibraryToLink; |
| } |
| staticLibraryToLink = |
| LinkerInputs.newInputLibrary( |
| getStaticLibrary(), |
| getAlwayslink() |
| ? ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY |
| : ArtifactCategory.STATIC_LIBRARY, |
| getLibraryIdentifier(), |
| getObjectFiles(), |
| getLtoCompilationContext(), |
| getSharedNonLtoBackends(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| return staticLibraryToLink; |
| } |
| |
| LinkerInputs.LibraryToLink getPicStaticLibraryToLink() { |
| Preconditions.checkNotNull(getPicStaticLibrary(), this); |
| if (picStaticLibraryToLink != null) { |
| return picStaticLibraryToLink; |
| } |
| picStaticLibraryToLink = |
| LinkerInputs.newInputLibrary( |
| getPicStaticLibrary(), |
| getAlwayslink() |
| ? ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY |
| : ArtifactCategory.STATIC_LIBRARY, |
| getLibraryIdentifier(), |
| getPicObjectFiles(), |
| getPicLtoCompilationContext(), |
| getPicSharedNonLtoBackends(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| return picStaticLibraryToLink; |
| } |
| |
| LinkerInputs.LibraryToLink getDynamicLibraryToLink() { |
| Preconditions.checkNotNull(getDynamicLibrary(), this); |
| if (dynamicLibraryToLink != null) { |
| return dynamicLibraryToLink; |
| } |
| if (getResolvedSymlinkDynamicLibrary() != null) { |
| dynamicLibraryToLink = |
| LinkerInputs.solibLibraryToLink( |
| getDynamicLibrary(), getResolvedSymlinkDynamicLibrary(), getLibraryIdentifier()); |
| } else { |
| dynamicLibraryToLink = |
| LinkerInputs.newInputLibrary( |
| getDynamicLibrary(), |
| ArtifactCategory.DYNAMIC_LIBRARY, |
| getLibraryIdentifier(), |
| /* objectFiles */ ImmutableSet.of(), |
| LtoCompilationContext.EMPTY, |
| /* sharedNonLtoBackends */ ImmutableMap.of(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| } |
| return dynamicLibraryToLink; |
| } |
| |
| LinkerInputs.LibraryToLink getInterfaceLibraryToLink() { |
| Preconditions.checkNotNull(getInterfaceLibrary()); |
| if (interfaceLibraryToLink != null) { |
| return interfaceLibraryToLink; |
| } |
| if (getResolvedSymlinkInterfaceLibrary() != null) { |
| interfaceLibraryToLink = |
| LinkerInputs.solibLibraryToLink( |
| getInterfaceLibrary(), getResolvedSymlinkInterfaceLibrary(), getLibraryIdentifier()); |
| } else { |
| interfaceLibraryToLink = |
| LinkerInputs.newInputLibrary( |
| getInterfaceLibrary(), |
| ArtifactCategory.INTERFACE_LIBRARY, |
| getLibraryIdentifier(), |
| /* objectFiles */ ImmutableSet.of(), |
| LtoCompilationContext.EMPTY, |
| /* sharedNonLtoBackends */ ImmutableMap.of(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| } |
| return interfaceLibraryToLink; |
| } |
| |
| public static List<Artifact> getDynamicLibrariesForRuntime( |
| boolean linkingStatically, Iterable<LibraryToLink> libraries) { |
| ImmutableList.Builder<Artifact> dynamicLibrariesForRuntimeBuilder = ImmutableList.builder(); |
| for (LibraryToLink libraryToLink : libraries) { |
| Artifact artifact = libraryToLink.getDynamicLibraryForRuntimeOrNull(linkingStatically); |
| if (artifact != null) { |
| dynamicLibrariesForRuntimeBuilder.add(artifact); |
| } |
| } |
| return dynamicLibrariesForRuntimeBuilder.build(); |
| } |
| |
| public static List<Artifact> getDynamicLibrariesForLinking(NestedSet<LibraryToLink> libraries) { |
| ImmutableList.Builder<Artifact> dynamicLibrariesForLinkingBuilder = ImmutableList.builder(); |
| for (LibraryToLink libraryToLink : libraries.toList()) { |
| if (libraryToLink.getInterfaceLibrary() != null) { |
| dynamicLibrariesForLinkingBuilder.add(libraryToLink.getInterfaceLibrary()); |
| } else if (libraryToLink.getDynamicLibrary() != null) { |
| dynamicLibrariesForLinkingBuilder.add(libraryToLink.getDynamicLibrary()); |
| } |
| } |
| return dynamicLibrariesForLinkingBuilder.build(); |
| } |
| |
| public abstract Builder toBuilder(); |
| |
| /** Builder for LibraryToLink. */ |
| @AutoValue.Builder |
| public abstract static class Builder { |
| |
| public abstract Builder setLibraryIdentifier(String libraryIdentifier); |
| |
| public abstract Builder setStaticLibrary(Artifact staticLibrary); |
| |
| public abstract Builder setObjectFiles(ImmutableList<Artifact> objectFiles); |
| |
| abstract Builder setLtoCompilationContext(LtoCompilationContext ltoCompilationContext); |
| |
| abstract Builder setSharedNonLtoBackends( |
| ImmutableMap<Artifact, LtoBackendArtifacts> sharedNonLtoBackends); |
| |
| abstract Builder setPicStaticLibrary(Artifact picStaticLibrary); |
| |
| abstract Builder setPicObjectFiles(ImmutableList<Artifact> picObjectFiles); |
| |
| abstract Builder setPicLtoCompilationContext(LtoCompilationContext picLtoCompilationContext); |
| |
| abstract Builder setPicSharedNonLtoBackends( |
| ImmutableMap<Artifact, LtoBackendArtifacts> picSharedNonLtoBackends); |
| |
| public abstract Builder setDynamicLibrary(Artifact dynamicLibrary); |
| |
| public abstract Builder setResolvedSymlinkDynamicLibrary( |
| Artifact resolvedSymlinkDynamicLibrary); |
| |
| public abstract Builder setInterfaceLibrary(Artifact interfaceLibrary); |
| |
| public abstract Builder setResolvedSymlinkInterfaceLibrary( |
| Artifact resolvedSymlinkInterfaceLibrary); |
| |
| public abstract Builder setAlwayslink(boolean alwayslink); |
| |
| public abstract Builder setMustKeepDebug(boolean mustKeepDebug); |
| |
| public abstract Builder setDisableWholeArchive(boolean disableWholeArchive); |
| |
| // Methods just for validation, not to be called externally. |
| abstract LibraryToLink autoBuild(); |
| |
| abstract String getLibraryIdentifier(); |
| |
| abstract Artifact getStaticLibrary(); |
| |
| abstract ImmutableList<Artifact> getObjectFiles(); |
| |
| abstract ImmutableMap<Artifact, LtoBackendArtifacts> getSharedNonLtoBackends(); |
| |
| abstract LtoCompilationContext getLtoCompilationContext(); |
| |
| abstract Artifact getPicStaticLibrary(); |
| |
| abstract ImmutableList<Artifact> getPicObjectFiles(); |
| |
| abstract ImmutableMap<Artifact, LtoBackendArtifacts> getPicSharedNonLtoBackends(); |
| |
| abstract LtoCompilationContext getPicLtoCompilationContext(); |
| |
| abstract Artifact getDynamicLibrary(); |
| |
| abstract Artifact getResolvedSymlinkDynamicLibrary(); |
| |
| abstract Artifact getInterfaceLibrary(); |
| |
| abstract Artifact getResolvedSymlinkInterfaceLibrary(); |
| |
| public LibraryToLink build() { |
| Preconditions.checkNotNull(getLibraryIdentifier()); |
| Preconditions.checkState( |
| (getObjectFiles() == null |
| && getLtoCompilationContext() == null |
| && getSharedNonLtoBackends() == null) |
| || getStaticLibrary() != null); |
| Preconditions.checkState( |
| (getPicObjectFiles() == null |
| && getPicLtoCompilationContext() == null |
| && getPicSharedNonLtoBackends() == null) |
| || getPicStaticLibrary() != null); |
| Preconditions.checkState( |
| getResolvedSymlinkDynamicLibrary() == null || getDynamicLibrary() != null); |
| Preconditions.checkState( |
| getResolvedSymlinkInterfaceLibrary() == null |
| || getResolvedSymlinkInterfaceLibrary() != null); |
| Preconditions.checkState( |
| getStaticLibrary() != null |
| || getPicStaticLibrary() != null |
| || getDynamicLibrary() != null |
| || getInterfaceLibrary() != null); |
| |
| return autoBuild(); |
| } |
| } |
| } |