| // 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. |
| |
| package com.google.devtools.build.lib.rules.cpp; |
| |
| import com.google.auto.value.AutoValue; |
| import com.google.auto.value.extension.memoized.Memoized; |
| 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.starlarkbuildapi.cpp.LibraryToLinkApi; |
| import javax.annotation.Nullable; |
| import net.starlark.java.eval.Dict; |
| import net.starlark.java.eval.EvalException; |
| import net.starlark.java.eval.Printer; |
| import net.starlark.java.eval.Sequence; |
| import net.starlark.java.eval.StarlarkList; |
| import net.starlark.java.eval.StarlarkSemantics; |
| import net.starlark.java.eval.StarlarkThread; |
| |
| /** Encapsulates information for linking a library. */ |
| // The AutoValue implementation of this class already has a sizeable number of fields, meaning that |
| // instances have a surprising memory cost. |
| @Immutable |
| public abstract class LibraryToLink implements LibraryToLinkApi<Artifact, LtoBackendArtifacts> { |
| |
| public static final Depset.ElementType TYPE = Depset.ElementType.of(LibraryToLink.class); |
| |
| public static ImmutableList<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 ImmutableList<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(); |
| } |
| |
| private LibraryToLink() {} |
| |
| public abstract String getLibraryIdentifier(); |
| |
| @Nullable |
| public abstract ImmutableList<Artifact> getObjectFiles(); |
| |
| @Nullable |
| public abstract ImmutableMap<Artifact, LtoBackendArtifacts> getSharedNonLtoBackends(); |
| |
| @Nullable |
| public abstract LtoCompilationContext getLtoCompilationContext(); |
| |
| @Nullable |
| public abstract ImmutableList<Artifact> getPicObjectFiles(); |
| |
| @Nullable |
| public abstract ImmutableMap<Artifact, LtoBackendArtifacts> getPicSharedNonLtoBackends(); |
| |
| @Nullable |
| public abstract LtoCompilationContext getPicLtoCompilationContext(); |
| |
| public abstract AutoLibraryToLink.Builder toBuilder(); |
| |
| @Override |
| public final boolean isImmutable() { |
| return true; // immutable and Starlark-hashable |
| } |
| |
| @Nullable |
| public final Artifact getDynamicLibraryForRuntimeOrNull(boolean linkingStatically) { |
| if (getDynamicLibrary() == null) { |
| return null; |
| } |
| if (linkingStatically && (getStaticLibrary() != null || getPicStaticLibrary() != null)) { |
| return null; |
| } |
| return getDynamicLibrary(); |
| } |
| |
| @Override |
| public final Sequence<Artifact> getObjectFilesForStarlark() { |
| ImmutableList<Artifact> objectFiles = getObjectFiles(); |
| return objectFiles == null ? StarlarkList.empty() : StarlarkList.immutableCopyOf(objectFiles); |
| } |
| |
| @Override |
| public final Sequence<Artifact> getLtoBitcodeFilesForStarlark() { |
| LtoCompilationContext ctx = getLtoCompilationContext(); |
| return ctx == null ? StarlarkList.empty() : StarlarkList.immutableCopyOf(ctx.getBitcodeFiles()); |
| } |
| |
| @Override |
| public final boolean getMustKeepDebugForStarlark(StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return getMustKeepDebug(); |
| } |
| |
| @Nullable |
| @Override |
| public final Dict<Artifact, LtoBackendArtifacts> getSharedNonLtoBackendsForStarlark( |
| StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| ImmutableMap<Artifact, LtoBackendArtifacts> backends = getSharedNonLtoBackends(); |
| return backends != null ? Dict.immutableCopyOf(backends) : null; |
| } |
| |
| @Override |
| public final Sequence<Artifact> getPicObjectFilesForStarlark() { |
| ImmutableList<Artifact> objectFiles = getPicObjectFiles(); |
| return objectFiles == null ? StarlarkList.empty() : StarlarkList.immutableCopyOf(objectFiles); |
| } |
| |
| @Override |
| public final Sequence<Artifact> getPicLtoBitcodeFilesForStarlark() { |
| LtoCompilationContext ctx = getPicLtoCompilationContext(); |
| return ctx == null ? StarlarkList.empty() : StarlarkList.immutableCopyOf(ctx.getBitcodeFiles()); |
| } |
| |
| @Nullable |
| @Override |
| public final Dict<Artifact, LtoBackendArtifacts> getPicSharedNonLtoBackendsForStarlark( |
| StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| ImmutableMap<Artifact, LtoBackendArtifacts> backends = getPicSharedNonLtoBackends(); |
| return backends != null ? Dict.immutableCopyOf(backends) : null; |
| } |
| |
| LinkerInputs.LibraryToLink getStaticLibraryToLink() { |
| return LinkerInputs.newInputLibrary( |
| Preconditions.checkNotNull(getStaticLibrary(), this), |
| getAlwayslink() |
| ? ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY |
| : ArtifactCategory.STATIC_LIBRARY, |
| getLibraryIdentifier(), |
| getObjectFiles(), |
| getLtoCompilationContext(), |
| getSharedNonLtoBackends(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| } |
| |
| LinkerInputs.LibraryToLink getPicStaticLibraryToLink() { |
| return LinkerInputs.newInputLibrary( |
| Preconditions.checkNotNull(getPicStaticLibrary(), this), |
| getAlwayslink() |
| ? ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY |
| : ArtifactCategory.STATIC_LIBRARY, |
| getLibraryIdentifier(), |
| getPicObjectFiles(), |
| getPicLtoCompilationContext(), |
| getPicSharedNonLtoBackends(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| } |
| |
| LinkerInputs.LibraryToLink getDynamicLibraryToLink() { |
| Artifact dynamicLibrary = Preconditions.checkNotNull(getDynamicLibrary(), this); |
| if (getResolvedSymlinkDynamicLibrary() != null) { |
| return LinkerInputs.solibLibraryToLink( |
| dynamicLibrary, getResolvedSymlinkDynamicLibrary(), getLibraryIdentifier()); |
| } |
| return LinkerInputs.newInputLibrary( |
| dynamicLibrary, |
| ArtifactCategory.DYNAMIC_LIBRARY, |
| getLibraryIdentifier(), |
| /*objectFiles=*/ ImmutableSet.of(), |
| LtoCompilationContext.EMPTY, |
| /*sharedNonLtoBackends=*/ ImmutableMap.of(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| } |
| |
| LinkerInputs.LibraryToLink getInterfaceLibraryToLink() { |
| Artifact interfaceLibrary = Preconditions.checkNotNull(getInterfaceLibrary(), this); |
| if (getResolvedSymlinkInterfaceLibrary() != null) { |
| return LinkerInputs.solibLibraryToLink( |
| interfaceLibrary, getResolvedSymlinkInterfaceLibrary(), getLibraryIdentifier()); |
| } |
| return LinkerInputs.newInputLibrary( |
| interfaceLibrary, |
| ArtifactCategory.INTERFACE_LIBRARY, |
| getLibraryIdentifier(), |
| /*objectFiles=*/ ImmutableSet.of(), |
| LtoCompilationContext.EMPTY, |
| /*sharedNonLtoBackends=*/ ImmutableMap.of(), |
| getMustKeepDebug(), |
| getDisableWholeArchive()); |
| } |
| |
| // 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 final void debugPrint(Printer printer, StarlarkSemantics semantics) { |
| 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(")>"); |
| } |
| |
| @Nullable |
| private static String mapEntry(String keyName, @Nullable Object value) { |
| return value == null ? null : keyName + "=" + value; |
| } |
| |
| public static AutoLibraryToLink.Builder builder() { |
| return new AutoValue_LibraryToLink_AutoLibraryToLink.Builder() |
| .setMustKeepDebug(false) |
| .setAlwayslink(false) |
| .setDisableWholeArchive(false); |
| } |
| |
| /** Builder for {@link LibraryToLink}. */ |
| public interface Builder { |
| |
| AutoLibraryToLink.Builder setLibraryIdentifier(String libraryIdentifier); |
| |
| AutoLibraryToLink.Builder setStaticLibrary(Artifact staticLibrary); |
| |
| AutoLibraryToLink.Builder setObjectFiles(ImmutableList<Artifact> objectFiles); |
| |
| AutoLibraryToLink.Builder setLtoCompilationContext(LtoCompilationContext ltoCompilationContext); |
| |
| AutoLibraryToLink.Builder setSharedNonLtoBackends( |
| ImmutableMap<Artifact, LtoBackendArtifacts> sharedNonLtoBackends); |
| |
| AutoLibraryToLink.Builder setPicStaticLibrary(Artifact picStaticLibrary); |
| |
| AutoLibraryToLink.Builder setPicObjectFiles(ImmutableList<Artifact> picObjectFiles); |
| |
| AutoLibraryToLink.Builder setPicLtoCompilationContext( |
| LtoCompilationContext picLtoCompilationContext); |
| |
| AutoLibraryToLink.Builder setPicSharedNonLtoBackends( |
| ImmutableMap<Artifact, LtoBackendArtifacts> picSharedNonLtoBackends); |
| |
| AutoLibraryToLink.Builder setDynamicLibrary(Artifact dynamicLibrary); |
| |
| AutoLibraryToLink.Builder setResolvedSymlinkDynamicLibrary( |
| Artifact resolvedSymlinkDynamicLibrary); |
| |
| AutoLibraryToLink.Builder setInterfaceLibrary(Artifact interfaceLibrary); |
| |
| AutoLibraryToLink.Builder setResolvedSymlinkInterfaceLibrary( |
| Artifact resolvedSymlinkInterfaceLibrary); |
| |
| AutoLibraryToLink.Builder setAlwayslink(boolean alwayslink); |
| |
| AutoLibraryToLink.Builder setMustKeepDebug(boolean mustKeepDebug); |
| |
| AutoLibraryToLink.Builder setDisableWholeArchive(boolean disableWholeArchive); |
| |
| LibraryToLink build(); |
| } |
| |
| /** {@link AutoValue}-backed implementation. */ |
| @AutoValue |
| abstract static class AutoLibraryToLink extends LibraryToLink { |
| |
| @Nullable |
| @Override // Remove @StarlarkMethod. |
| public abstract Artifact getStaticLibrary(); |
| |
| @Nullable |
| @Override // Remove @StarlarkMethod. |
| public abstract Artifact getPicStaticLibrary(); |
| |
| @Nullable |
| @Override // Remove @StarlarkMethod. |
| public abstract Artifact getDynamicLibrary(); |
| |
| @Nullable |
| @Override // Remove @StarlarkMethod. |
| public abstract Artifact getResolvedSymlinkDynamicLibrary(); |
| |
| @Nullable |
| @Override // Remove @StarlarkMethod. |
| public abstract Artifact getInterfaceLibrary(); |
| |
| @Nullable |
| @Override // Remove @StarlarkMethod. |
| public abstract Artifact getResolvedSymlinkInterfaceLibrary(); |
| |
| @Override // Remove @StarlarkMethod. |
| public abstract boolean getAlwayslink(); |
| |
| @Memoized |
| @Override |
| LinkerInputs.LibraryToLink getStaticLibraryToLink() { |
| return super.getStaticLibraryToLink(); |
| } |
| |
| @Memoized |
| @Override |
| LinkerInputs.LibraryToLink getPicStaticLibraryToLink() { |
| return super.getPicStaticLibraryToLink(); |
| } |
| |
| @Memoized |
| @Override |
| LinkerInputs.LibraryToLink getDynamicLibraryToLink() { |
| return super.getDynamicLibraryToLink(); |
| } |
| |
| @Memoized |
| @Override |
| LinkerInputs.LibraryToLink getInterfaceLibraryToLink() { |
| return super.getInterfaceLibraryToLink(); |
| } |
| |
| @AutoValue.Builder |
| public abstract static class Builder implements LibraryToLink.Builder { |
| |
| Builder() {} |
| |
| abstract AutoLibraryToLink autoBuild(); |
| |
| @Override |
| public final LibraryToLink build() { |
| LibraryToLink result = autoBuild(); |
| Preconditions.checkNotNull(result.getLibraryIdentifier(), result); |
| Preconditions.checkState( |
| result.getResolvedSymlinkDynamicLibrary() == null || result.getDynamicLibrary() != null, |
| result); |
| Preconditions.checkState( |
| result.getResolvedSymlinkInterfaceLibrary() == null |
| || result.getResolvedSymlinkInterfaceLibrary() != null, |
| result); |
| Preconditions.checkState( |
| result.getStaticLibrary() != null |
| || result.getPicStaticLibrary() != null |
| || result.getDynamicLibrary() != null |
| || result.getInterfaceLibrary() != null, |
| result); |
| |
| return result; |
| } |
| } |
| } |
| } |