| // Copyright 2014 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.Objects; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.collect.nestedset.Depset; |
| import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; |
| import com.google.devtools.build.lib.packages.BuiltinProvider; |
| import com.google.devtools.build.lib.packages.NativeInfo; |
| import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcInfoApi; |
| import com.google.errorprone.annotations.CanIgnoreReturnValue; |
| import java.util.Collection; |
| import javax.annotation.Nullable; |
| import net.starlark.java.eval.EvalException; |
| import net.starlark.java.eval.Starlark; |
| import net.starlark.java.eval.StarlarkThread; |
| |
| /** Provider for C++ compilation and linking information. */ |
| @Immutable |
| public final class CcInfo extends NativeInfo implements CcInfoApi<Artifact> { |
| public static final Provider PROVIDER = new Provider(); |
| public static final CcInfo EMPTY = builder().build(); |
| |
| private final CcCompilationContext ccCompilationContext; |
| private final CcLinkingContext ccLinkingContext; |
| private final CcDebugInfoContext ccDebugInfoContext; |
| private final CcNativeLibraryInfo ccNativeLibraryInfo; |
| |
| public CcInfo( |
| CcCompilationContext ccCompilationContext, |
| CcLinkingContext ccLinkingContext, |
| CcDebugInfoContext ccDebugInfoContext, |
| CcNativeLibraryInfo ccNativeLibraryInfo) { |
| this.ccCompilationContext = ccCompilationContext; |
| this.ccLinkingContext = ccLinkingContext; |
| this.ccDebugInfoContext = ccDebugInfoContext; |
| this.ccNativeLibraryInfo = ccNativeLibraryInfo; |
| } |
| |
| @Override |
| public Provider getProvider() { |
| return PROVIDER; |
| } |
| |
| @Override |
| public CcCompilationContext getCcCompilationContext() { |
| return ccCompilationContext; |
| } |
| |
| @Override |
| public CcLinkingContext getCcLinkingContext() { |
| return ccLinkingContext; |
| } |
| |
| @Override |
| public CcDebugInfoContext getCcDebugInfoContextFromStarlark(StarlarkThread thread) |
| throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return getCcDebugInfoContext(); |
| } |
| |
| @Override |
| public Depset getCcTransitiveNativeLibraries(StarlarkThread thread) throws EvalException { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| return Depset.of( |
| LibraryToLink.class, getCcNativeLibraryInfo().getTransitiveCcNativeLibraries()); |
| } |
| |
| public CcDebugInfoContext getCcDebugInfoContext() { |
| return ccDebugInfoContext; |
| } |
| |
| public CcNativeLibraryInfo getCcNativeLibraryInfo() { |
| return ccNativeLibraryInfo; |
| } |
| |
| public static CcInfo merge(Collection<CcInfo> ccInfos) { |
| return merge(ImmutableList.of(), ccInfos); |
| } |
| |
| public static CcInfo merge(Collection<CcInfo> directCcInfos, Collection<CcInfo> ccInfos) { |
| ImmutableList.Builder<CcCompilationContext> directCcCompilationContexts = |
| ImmutableList.builder(); |
| ImmutableList.Builder<CcCompilationContext> ccCompilationContexts = ImmutableList.builder(); |
| ImmutableList.Builder<CcLinkingContext> ccLinkingContexts = ImmutableList.builder(); |
| ImmutableList.Builder<CcDebugInfoContext> ccDebugInfoContexts = ImmutableList.builder(); |
| ImmutableList.Builder<CcNativeLibraryInfo> ccNativeLibraryInfos = ImmutableList.builder(); |
| |
| for (CcInfo ccInfo : directCcInfos) { |
| directCcCompilationContexts.add(ccInfo.getCcCompilationContext()); |
| ccLinkingContexts.add(ccInfo.getCcLinkingContext()); |
| ccDebugInfoContexts.add(ccInfo.getCcDebugInfoContext()); |
| ccNativeLibraryInfos.add(ccInfo.getCcNativeLibraryInfo()); |
| } |
| for (CcInfo ccInfo : ccInfos) { |
| ccCompilationContexts.add(ccInfo.getCcCompilationContext()); |
| ccLinkingContexts.add(ccInfo.getCcLinkingContext()); |
| ccDebugInfoContexts.add(ccInfo.getCcDebugInfoContext()); |
| ccNativeLibraryInfos.add(ccInfo.getCcNativeLibraryInfo()); |
| } |
| |
| CcCompilationContext.Builder builder = |
| CcCompilationContext.builder( |
| /* actionConstructionContext= */ null, /* configuration= */ null, /* label= */ null); |
| |
| return new CcInfo( |
| builder |
| .addDependentCcCompilationContexts( |
| directCcCompilationContexts.build(), ccCompilationContexts.build()) |
| .build(), |
| CcLinkingContext.merge(ccLinkingContexts.build()), |
| CcDebugInfoContext.merge(ccDebugInfoContexts.build()), |
| CcNativeLibraryInfo.merge(ccNativeLibraryInfos.build())); |
| } |
| |
| @Override |
| public boolean equals(Object otherObject) { |
| if (!(otherObject instanceof CcInfo)) { |
| return false; |
| } |
| CcInfo other = (CcInfo) otherObject; |
| if (this == other) { |
| return true; |
| } |
| if (!this.ccCompilationContext.equals(other.ccCompilationContext) |
| || !this.ccDebugInfoContext.equals(other.ccDebugInfoContext) |
| || !this.getCcLinkingContext().equals(other.getCcLinkingContext()) |
| || !this.getCcNativeLibraryInfo().equals(other.getCcNativeLibraryInfo())) { |
| return false; |
| } |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hashCode(ccCompilationContext, ccLinkingContext, ccDebugInfoContext); |
| } |
| |
| public static Builder builder() { |
| // private to avoid class initialization deadlock between this class and its outer class |
| return new Builder(); |
| } |
| |
| /** A Builder for {@link CcInfo}. */ |
| public static class Builder { |
| private CcCompilationContext ccCompilationContext; |
| private CcLinkingContext ccLinkingContext; |
| private CcDebugInfoContext ccDebugInfoContext; |
| private CcNativeLibraryInfo ccNativeLibraryInfo; |
| |
| private Builder() {} |
| |
| @CanIgnoreReturnValue |
| public CcInfo.Builder setCcCompilationContext(CcCompilationContext ccCompilationContext) { |
| Preconditions.checkState(this.ccCompilationContext == null); |
| this.ccCompilationContext = ccCompilationContext; |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public CcInfo.Builder setCcLinkingContext(CcLinkingContext ccLinkingContext) { |
| Preconditions.checkState(this.ccLinkingContext == null); |
| this.ccLinkingContext = ccLinkingContext; |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public CcInfo.Builder setCcDebugInfoContext(CcDebugInfoContext ccDebugInfoContext) { |
| Preconditions.checkState(this.ccDebugInfoContext == null); |
| this.ccDebugInfoContext = ccDebugInfoContext; |
| return this; |
| } |
| |
| @CanIgnoreReturnValue |
| public CcInfo.Builder setCcNativeLibraryInfo(CcNativeLibraryInfo ccNativeLibraryInfo) { |
| Preconditions.checkState(this.ccNativeLibraryInfo == null); |
| this.ccNativeLibraryInfo = ccNativeLibraryInfo; |
| return this; |
| } |
| |
| public CcInfo build() { |
| if (ccCompilationContext == null) { |
| ccCompilationContext = CcCompilationContext.EMPTY; |
| } |
| if (ccLinkingContext == null) { |
| ccLinkingContext = CcLinkingContext.EMPTY; |
| } |
| if (ccDebugInfoContext == null) { |
| ccDebugInfoContext = CcDebugInfoContext.EMPTY; |
| } |
| if (ccNativeLibraryInfo == null) { |
| ccNativeLibraryInfo = CcNativeLibraryInfo.EMPTY; |
| } |
| return new CcInfo( |
| ccCompilationContext, ccLinkingContext, ccDebugInfoContext, ccNativeLibraryInfo); |
| } |
| } |
| |
| /** Provider class for {@link CcInfo} objects. */ |
| public static class Provider extends BuiltinProvider<CcInfo> |
| implements CcInfoApi.Provider<Artifact> { |
| private Provider() { |
| super(CcInfoApi.NAME, CcInfo.class); |
| } |
| |
| @Override |
| public CcInfoApi<Artifact> createInfo( |
| Object starlarkCcCompilationContext, |
| Object starlarkCcLinkingInfo, |
| Object starlarkCcDebugInfo, |
| Object starlarkCcNativeLibraryInfo, |
| StarlarkThread thread) |
| throws EvalException { |
| CcCompilationContext ccCompilationContext = |
| nullIfNone(starlarkCcCompilationContext, CcCompilationContext.class); |
| CcLinkingContext ccLinkingContext = nullIfNone(starlarkCcLinkingInfo, CcLinkingContext.class); |
| CcDebugInfoContext ccDebugInfoContext = |
| nullIfNone(starlarkCcDebugInfo, CcDebugInfoContext.class); |
| CcNativeLibraryInfo ccNativeLibraryInfo = |
| nullIfNone(starlarkCcNativeLibraryInfo, CcNativeLibraryInfo.class); |
| CcInfo.Builder ccInfoBuilder = CcInfo.builder(); |
| if (ccCompilationContext != null) { |
| ccInfoBuilder.setCcCompilationContext(ccCompilationContext); |
| } |
| if (ccLinkingContext != null) { |
| ccInfoBuilder.setCcLinkingContext(ccLinkingContext); |
| } |
| if (ccDebugInfoContext != null) { |
| ccInfoBuilder.setCcDebugInfoContext(ccDebugInfoContext); |
| } |
| if (ccNativeLibraryInfo != null) { |
| CcModule.checkPrivateStarlarkificationAllowlist(thread); |
| ccInfoBuilder.setCcNativeLibraryInfo(ccNativeLibraryInfo); |
| } |
| return ccInfoBuilder.build(); |
| } |
| |
| @Nullable |
| private static <T> T nullIfNone(Object object, Class<T> type) { |
| return object != Starlark.NONE ? type.cast(object) : null; |
| } |
| } |
| } |