| // Copyright 2019 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.common.base.Joiner; |
| import com.google.common.base.MoreObjects; |
| import com.google.common.base.Objects; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.actions.ActionKeyContext; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.actions.CommandLineExpansionException; |
| import com.google.devtools.build.lib.bugreport.BugReport; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.collect.nestedset.Depset; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; |
| import com.google.devtools.build.lib.packages.SymbolGenerator; |
| import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions; |
| import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcLinkingContextApi; |
| import com.google.devtools.build.lib.starlarkbuildapi.cpp.ExtraLinkTimeLibraryApi; |
| import com.google.devtools.build.lib.starlarkbuildapi.cpp.LinkerInputApi; |
| import com.google.devtools.build.lib.starlarkbuildapi.cpp.LinkstampApi; |
| import com.google.devtools.build.lib.util.Fingerprint; |
| import com.google.errorprone.annotations.CanIgnoreReturnValue; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.List; |
| import javax.annotation.Nullable; |
| import net.starlark.java.annot.StarlarkMethod; |
| import net.starlark.java.eval.EvalException; |
| import net.starlark.java.eval.Printer; |
| import net.starlark.java.eval.Sequence; |
| import net.starlark.java.eval.Starlark; |
| import net.starlark.java.eval.StarlarkList; |
| import net.starlark.java.eval.StarlarkSemantics; |
| import net.starlark.java.eval.StarlarkThread; |
| |
| /** Structure of CcLinkingContext. */ |
| public class CcLinkingContext implements CcLinkingContextApi<Artifact> { |
| public static final CcLinkingContext EMPTY = builder().build(); |
| |
| /** A list of link options contributed by a single configured target/aspect. */ |
| @Immutable |
| public static final class LinkOptions { |
| private final ImmutableList<String> linkOptions; |
| private final Object symbolForEquality; |
| |
| private LinkOptions(ImmutableList<String> linkOptions, Object symbolForEquality) { |
| this.linkOptions = Preconditions.checkNotNull(linkOptions); |
| this.symbolForEquality = Preconditions.checkNotNull(symbolForEquality); |
| } |
| |
| public ImmutableList<String> get() { |
| return linkOptions; |
| } |
| |
| public static LinkOptions of( |
| ImmutableList<String> linkOptions, SymbolGenerator<?> symbolGenerator) { |
| return new LinkOptions(linkOptions, symbolGenerator.generate()); |
| } |
| |
| @Override |
| public int hashCode() { |
| // Symbol is sufficient for equality check. |
| return symbolForEquality.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (!(obj instanceof LinkOptions)) { |
| return false; |
| } |
| LinkOptions that = (LinkOptions) obj; |
| if (!this.symbolForEquality.equals(that.symbolForEquality)) { |
| return false; |
| } |
| if (this.linkOptions.equals(that.linkOptions)) { |
| return true; |
| } |
| BugReport.sendBugReport( |
| new IllegalStateException( |
| "Unexpected inequality with equal symbols: " + this + ", " + that)); |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return '[' + Joiner.on(",").join(linkOptions) + "] (owner: " + symbolForEquality; |
| } |
| } |
| |
| /** |
| * A linkstamp that also knows about its declared includes. |
| * |
| * <p>This object is required because linkstamp files may include other headers which will have to |
| * be provided during compilation. |
| */ |
| @Immutable |
| public static final class Linkstamp implements LinkstampApi<Artifact> { |
| private final Artifact artifact; |
| private final NestedSet<Artifact> declaredIncludeSrcs; |
| private final byte[] nestedDigest; |
| |
| public static final Depset.ElementType TYPE = Depset.ElementType.of(Linkstamp.class); |
| |
| // TODO(janakr): if action key context is not available, the digest can be computed lazily, |
| // only if we are doing an equality comparison and artifacts are equal. That should never |
| // happen, so doing an expensive digest should be ok then. If this is ever moved to Starlark |
| // and Starlark doesn't support custom equality or amortized deep equality of nested sets, a |
| // Symbol can be used as an equality proxy, similar to what LinkOptions does above. |
| Linkstamp( |
| Artifact artifact, |
| NestedSet<Artifact> declaredIncludeSrcs, |
| ActionKeyContext actionKeyContext) |
| throws CommandLineExpansionException, InterruptedException { |
| this.artifact = Preconditions.checkNotNull(artifact); |
| this.declaredIncludeSrcs = Preconditions.checkNotNull(declaredIncludeSrcs); |
| Fingerprint fp = new Fingerprint(); |
| actionKeyContext.addNestedSetToFingerprint(fp, this.declaredIncludeSrcs); |
| nestedDigest = fp.digestAndReset(); |
| } |
| |
| /** Returns the linkstamp artifact. */ |
| public Artifact getArtifact() { |
| return artifact; |
| } |
| |
| @Override |
| public Artifact getArtifactForStarlark(StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return artifact; |
| } |
| |
| /** Returns the declared includes. */ |
| public NestedSet<Artifact> getDeclaredIncludeSrcs() { |
| return declaredIncludeSrcs; |
| } |
| |
| @Override |
| public Depset getDeclaredIncludeSrcsForStarlark(StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return Depset.of(Artifact.TYPE, getDeclaredIncludeSrcs()); |
| } |
| |
| @Override |
| public int hashCode() { |
| // Artifact should be enough to disambiguate basically all the time. |
| return artifact.hashCode(); |
| } |
| |
| @Override |
| public final boolean isImmutable() { |
| return true; // immutable and Starlark-hashable |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (!(obj instanceof Linkstamp)) { |
| return false; |
| } |
| Linkstamp other = (Linkstamp) obj; |
| return artifact.equals(other.artifact) |
| && Arrays.equals(this.nestedDigest, other.nestedDigest); |
| } |
| } |
| |
| /** |
| * Wraps any input to the linker, be it libraries, linker scripts, linkstamps or linking options. |
| */ |
| // TODO(bazel-team): choose less confusing names for this class and the package-level interface of |
| // the same name. |
| @Immutable |
| public static class LinkerInput |
| implements LinkerInputApi<LibraryToLink, LtoBackendArtifacts, Artifact> { |
| |
| public static final Depset.ElementType TYPE = Depset.ElementType.of(LinkerInput.class); |
| |
| // Identifies which target created the LinkerInput. It doesn't have to be unique between |
| // LinkerInputs. |
| private final Label owner; |
| private final ImmutableList<LibraryToLink> libraries; |
| private final ImmutableList<LinkOptions> userLinkFlags; |
| private final ImmutableList<Artifact> nonCodeInputs; |
| private final ImmutableList<Linkstamp> linkstamps; |
| |
| public LinkerInput( |
| Label owner, |
| ImmutableList<LibraryToLink> libraries, |
| ImmutableList<LinkOptions> userLinkFlags, |
| ImmutableList<Artifact> nonCodeInputs, |
| ImmutableList<Linkstamp> linkstamps) { |
| this.owner = owner; |
| this.libraries = libraries; |
| this.userLinkFlags = userLinkFlags; |
| this.nonCodeInputs = nonCodeInputs; |
| this.linkstamps = linkstamps; |
| } |
| |
| @Override |
| public boolean isImmutable() { |
| return true; // immutable and Starlark-hashable |
| } |
| |
| @Override |
| public Label getStarlarkOwner() throws EvalException { |
| if (owner == null) { |
| throw Starlark.errorf( |
| "Owner is null. This means that some target upstream is of a rule type that uses the" |
| + " old API of create_linking_context"); |
| } |
| return owner; |
| } |
| |
| public Label getOwner() { |
| return owner; |
| } |
| |
| public List<LibraryToLink> getLibraries() { |
| return libraries; |
| } |
| |
| @Override |
| public Sequence<LibraryToLink> getStarlarkLibrariesToLink(StarlarkSemantics semantics) { |
| return StarlarkList.immutableCopyOf(getLibraries()); |
| } |
| |
| public List<LinkOptions> getUserLinkFlags() { |
| return userLinkFlags; |
| } |
| |
| @Override |
| public Sequence<String> getStarlarkUserLinkFlags() { |
| return StarlarkList.immutableCopyOf( |
| getUserLinkFlags().stream() |
| .map(LinkOptions::get) |
| .flatMap(Collection::stream) |
| .collect(ImmutableList.toImmutableList())); |
| } |
| |
| public List<Artifact> getNonCodeInputs() { |
| return nonCodeInputs; |
| } |
| |
| @Override |
| public Sequence<Artifact> getStarlarkNonCodeInputs() { |
| return StarlarkList.immutableCopyOf(getNonCodeInputs()); |
| } |
| |
| public List<Linkstamp> getLinkstamps() { |
| return linkstamps; |
| } |
| |
| @StarlarkMethod(name = "linkstamps", documented = false, structField = true) |
| public Sequence<Linkstamp> getLinkstampsForStarlark() { |
| return StarlarkList.immutableCopyOf(getLinkstamps()); |
| } |
| |
| @Override |
| public void debugPrint(Printer printer, StarlarkSemantics semantics) { |
| printer.append("<LinkerInput(owner="); |
| if (owner == null) { |
| printer.append("[null owner, uses old create_linking_context API]"); |
| } else { |
| owner.debugPrint(printer, semantics); |
| } |
| printer.append(", libraries=["); |
| for (LibraryToLink libraryToLink : libraries) { |
| libraryToLink.debugPrint(printer, semantics); |
| printer.append(", "); |
| } |
| printer.append("], userLinkFlags=["); |
| printer.append(Joiner.on(", ").join(userLinkFlags)); |
| printer.append("], nonCodeInputs=["); |
| for (Artifact nonCodeInput : nonCodeInputs) { |
| nonCodeInput.debugPrint(printer, semantics); |
| printer.append(", "); |
| } |
| // TODO(cparsons): Add debug repesentation of linkstamps. |
| printer.append("])>"); |
| } |
| |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| /** Builder for {@link LinkerInput} */ |
| public static class Builder { |
| private Label owner; |
| private final ImmutableList.Builder<LibraryToLink> libraries = ImmutableList.builder(); |
| private final ImmutableList.Builder<LinkOptions> userLinkFlags = ImmutableList.builder(); |
| private final ImmutableList.Builder<Artifact> nonCodeInputs = ImmutableList.builder(); |
| private final ImmutableList.Builder<Linkstamp> linkstamps = ImmutableList.builder(); |
| |
| @CanIgnoreReturnValue |
| public Builder addLibrary(LibraryToLink library) { |
| this.libraries.add(library); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addLibraries(List<LibraryToLink> libraries) { |
| this.libraries.addAll(libraries); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addUserLinkFlags(List<LinkOptions> userLinkFlags) { |
| this.userLinkFlags.addAll(userLinkFlags); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addLinkstamps(List<Linkstamp> linkstamps) { |
| this.linkstamps.addAll(linkstamps); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addNonCodeInputs(List<Artifact> nonCodeInputs) { |
| this.nonCodeInputs.addAll(nonCodeInputs); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder setOwner(Label owner) { |
| this.owner = owner; |
| return this; |
| } |
| |
| public LinkerInput build() { |
| return new LinkerInput( |
| owner, |
| libraries.build(), |
| userLinkFlags.build(), |
| nonCodeInputs.build(), |
| linkstamps.build()); |
| } |
| } |
| |
| @Override |
| public boolean equals(Object otherObject) { |
| if (!(otherObject instanceof LinkerInput)) { |
| return false; |
| } |
| LinkerInput other = (LinkerInput) otherObject; |
| if (this == other) { |
| return true; |
| } |
| return Objects.equal(this.owner, other.owner) |
| && this.libraries.equals(other.libraries) |
| && this.userLinkFlags.equals(other.userLinkFlags) |
| && this.linkstamps.equals(other.linkstamps) |
| && this.nonCodeInputs.equals(other.nonCodeInputs); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hashCode( |
| libraries.hashCode(), |
| userLinkFlags.hashCode(), |
| linkstamps.hashCode(), |
| nonCodeInputs.hashCode()); |
| } |
| |
| @Override |
| public String toString() { |
| return MoreObjects.toStringHelper(this) |
| .add("userLinkFlags", userLinkFlags) |
| .add("linkstamps", linkstamps) |
| .add("libraries", libraries) |
| .add("nonCodeInputs", nonCodeInputs) |
| .toString(); |
| } |
| } |
| |
| private final NestedSet<LinkerInput> linkerInputs; |
| @Nullable private final ExtraLinkTimeLibraries extraLinkTimeLibraries; |
| |
| @Override |
| public void debugPrint(Printer printer, StarlarkSemantics semantics) { |
| printer.append("<CcLinkingContext(["); |
| for (LinkerInput linkerInput : linkerInputs.toList()) { |
| linkerInput.debugPrint(printer, semantics); |
| printer.append(", "); |
| } |
| printer.append("])>"); |
| } |
| |
| public CcLinkingContext( |
| NestedSet<LinkerInput> linkerInputs, |
| @Nullable ExtraLinkTimeLibraries extraLinkTimeLibraries) { |
| this.linkerInputs = linkerInputs; |
| this.extraLinkTimeLibraries = extraLinkTimeLibraries; |
| } |
| |
| public static CcLinkingContext merge(List<CcLinkingContext> ccLinkingContexts) { |
| Builder mergedCcLinkingContext = CcLinkingContext.builder(); |
| ExtraLinkTimeLibraries.Builder mergedExtraLinkTimeLibraries = ExtraLinkTimeLibraries.builder(); |
| for (CcLinkingContext ccLinkingContext : ccLinkingContexts) { |
| mergedCcLinkingContext.addTransitiveLinkerInputs(ccLinkingContext.getLinkerInputs()); |
| if (ccLinkingContext.getExtraLinkTimeLibraries() != null) { |
| mergedExtraLinkTimeLibraries.addTransitive(ccLinkingContext.getExtraLinkTimeLibraries()); |
| } |
| } |
| mergedCcLinkingContext.setExtraLinkTimeLibraries(mergedExtraLinkTimeLibraries.build()); |
| return mergedCcLinkingContext.build(); |
| } |
| |
| public List<Artifact> getStaticModeParamsForExecutableLibraries() { |
| ImmutableList.Builder<Artifact> libraryListBuilder = ImmutableList.builder(); |
| for (LibraryToLink libraryToLink : getLibraries().toList()) { |
| if (libraryToLink.getStaticLibrary() != null) { |
| libraryListBuilder.add(libraryToLink.getStaticLibrary()); |
| } else if (libraryToLink.getPicStaticLibrary() != null) { |
| libraryListBuilder.add(libraryToLink.getPicStaticLibrary()); |
| } else if (libraryToLink.getInterfaceLibrary() != null) { |
| libraryListBuilder.add(libraryToLink.getInterfaceLibrary()); |
| } else { |
| libraryListBuilder.add(libraryToLink.getDynamicLibrary()); |
| } |
| } |
| return libraryListBuilder.build(); |
| } |
| |
| public List<Artifact> getStaticModeParamsForDynamicLibraryLibraries() { |
| ImmutableList.Builder<Artifact> artifactListBuilder = ImmutableList.builder(); |
| for (LibraryToLink library : getLibraries().toList()) { |
| if (library.getPicStaticLibrary() != null) { |
| artifactListBuilder.add(library.getPicStaticLibrary()); |
| } else if (library.getStaticLibrary() != null) { |
| artifactListBuilder.add(library.getStaticLibrary()); |
| } else if (library.getInterfaceLibrary() != null) { |
| artifactListBuilder.add(library.getInterfaceLibrary()); |
| } else { |
| artifactListBuilder.add(library.getDynamicLibrary()); |
| } |
| } |
| return artifactListBuilder.build(); |
| } |
| |
| public List<Artifact> getDynamicLibrariesForRuntime(boolean linkingStatically) { |
| return LibraryToLink.getDynamicLibrariesForRuntime(linkingStatically, getLibraries().toList()); |
| } |
| |
| public NestedSet<LibraryToLink> getLibraries() { |
| NestedSetBuilder<LibraryToLink> libraries = NestedSetBuilder.linkOrder(); |
| for (LinkerInput linkerInput : linkerInputs.toList()) { |
| libraries.addAll(linkerInput.libraries); |
| } |
| return libraries.build(); |
| } |
| |
| public NestedSet<LinkerInput> getLinkerInputs() { |
| return linkerInputs; |
| } |
| |
| @Override |
| public Depset getStarlarkLinkerInputs() { |
| return Depset.of(LinkerInput.TYPE, linkerInputs); |
| } |
| |
| @Override |
| public Sequence<String> getStarlarkUserLinkFlags() { |
| return StarlarkList.immutableCopyOf(getFlattenedUserLinkFlags()); |
| } |
| |
| @Override |
| public Object getStarlarkLibrariesToLink(StarlarkSemantics semantics) { |
| // TODO(plf): Flag can be removed already. |
| if (semantics.getBool(BuildLanguageOptions.INCOMPATIBLE_DEPSET_FOR_LIBRARIES_TO_LINK_GETTER)) { |
| return Depset.of(LibraryToLink.TYPE, getLibraries()); |
| } else { |
| return StarlarkList.immutableCopyOf(getLibraries().toList()); |
| } |
| } |
| |
| @Override |
| public Depset getStarlarkNonCodeInputs() { |
| return Depset.of(Artifact.TYPE, getNonCodeInputs()); |
| } |
| |
| @Override |
| public ExtraLinkTimeLibraryApi getGoLinkCArchiveForStarlark(StarlarkThread thread) |
| throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| ExtraLinkTimeLibrary goLinkCArchive = null; |
| if (extraLinkTimeLibraries != null) { |
| for (ExtraLinkTimeLibrary extraLibrary : extraLinkTimeLibraries.getExtraLibraries()) { |
| if (goLinkCArchive != null) { |
| throw new EvalException("multiple GoLinkCArchive entries in go_link_c_archive"); |
| } |
| goLinkCArchive = extraLibrary; |
| } |
| } |
| return goLinkCArchive; |
| } |
| |
| public NestedSet<LinkOptions> getUserLinkFlags() { |
| NestedSetBuilder<LinkOptions> userLinkFlags = NestedSetBuilder.linkOrder(); |
| for (LinkerInput linkerInput : linkerInputs.toList()) { |
| userLinkFlags.addAll(linkerInput.getUserLinkFlags()); |
| } |
| return userLinkFlags.build(); |
| } |
| |
| public ImmutableList<String> getFlattenedUserLinkFlags() { |
| return getUserLinkFlags().toList().stream() |
| .map(LinkOptions::get) |
| .flatMap(Collection::stream) |
| .collect(ImmutableList.toImmutableList()); |
| } |
| |
| public NestedSet<Linkstamp> getLinkstamps() { |
| NestedSetBuilder<Linkstamp> linkstamps = NestedSetBuilder.linkOrder(); |
| for (LinkerInput linkerInput : linkerInputs.toList()) { |
| linkstamps.addAll(linkerInput.getLinkstamps()); |
| } |
| return linkstamps.build(); |
| } |
| |
| @Override |
| public Depset getLinkstampsForStarlark(StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return Depset.of(Linkstamp.TYPE, getLinkstamps()); |
| } |
| |
| public NestedSet<Artifact> getNonCodeInputs() { |
| NestedSetBuilder<Artifact> nonCodeInputs = NestedSetBuilder.linkOrder(); |
| for (LinkerInput linkerInput : linkerInputs.toList()) { |
| nonCodeInputs.addAll(linkerInput.getNonCodeInputs()); |
| } |
| return nonCodeInputs.build(); |
| } |
| |
| public ExtraLinkTimeLibraries getExtraLinkTimeLibraries() { |
| return extraLinkTimeLibraries; |
| } |
| |
| @Override |
| public ExtraLinkTimeLibraries getExtraLinkTimeLibrariesForStarlark(StarlarkThread thread) |
| throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return getExtraLinkTimeLibraries(); |
| } |
| |
| public static Builder builder() { |
| // private to avoid class initialization deadlock between this class and its outer class |
| return new Builder(); |
| } |
| |
| /** Builder for {@link CcLinkingContext}. */ |
| public static class Builder { |
| boolean hasDirectLinkerInput; |
| LinkerInput.Builder linkerInputBuilder = LinkerInput.builder(); |
| private final NestedSetBuilder<LinkerInput> linkerInputs = NestedSetBuilder.linkOrder(); |
| private ExtraLinkTimeLibraries extraLinkTimeLibraries = null; |
| |
| @CanIgnoreReturnValue |
| public Builder setOwner(Label owner) { |
| linkerInputBuilder.setOwner(owner); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addLibrary(LibraryToLink library) { |
| hasDirectLinkerInput = true; |
| linkerInputBuilder.addLibrary(library); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addLibraries(List<LibraryToLink> libraries) { |
| hasDirectLinkerInput = true; |
| linkerInputBuilder.addLibraries(libraries); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addUserLinkFlags(List<LinkOptions> userLinkFlags) { |
| hasDirectLinkerInput = true; |
| linkerInputBuilder.addUserLinkFlags(userLinkFlags); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addLinkstamps(List<Linkstamp> linkstamps) { |
| hasDirectLinkerInput = true; |
| linkerInputBuilder.addLinkstamps(linkstamps); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| Builder addNonCodeInputs(List<Artifact> nonCodeInputs) { |
| hasDirectLinkerInput = true; |
| linkerInputBuilder.addNonCodeInputs(nonCodeInputs); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder addTransitiveLinkerInputs(NestedSet<LinkerInput> linkerInputs) { |
| this.linkerInputs.addTransitive(linkerInputs); |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public Builder setExtraLinkTimeLibraries(ExtraLinkTimeLibraries extraLinkTimeLibraries) { |
| Preconditions.checkState(this.extraLinkTimeLibraries == null); |
| this.extraLinkTimeLibraries = extraLinkTimeLibraries; |
| return this; |
| } |
| |
| public CcLinkingContext build() { |
| if (hasDirectLinkerInput) { |
| linkerInputs.add(linkerInputBuilder.build()); |
| } |
| return new CcLinkingContext(linkerInputs.build(), extraLinkTimeLibraries); |
| } |
| } |
| |
| @Override |
| public boolean equals(Object otherObject) { |
| if (!(otherObject instanceof CcLinkingContext)) { |
| return false; |
| } |
| CcLinkingContext other = (CcLinkingContext) otherObject; |
| if (this == other) { |
| return true; |
| } |
| return this.linkerInputs.shallowEquals(other.linkerInputs); |
| } |
| |
| @Override |
| public int hashCode() { |
| return linkerInputs.shallowHashCode(); |
| } |
| |
| @Override |
| public String toString() { |
| return MoreObjects.toStringHelper(this).add("linkerInputs", linkerInputs).toString(); |
| } |
| } |