blob: d456c5964cbd43aabcf52d9f4d806dc638c4e57c [file] [log] [blame]
// 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;
}
}
}
}