blob: 2420973506e02f0bf85ec7fc1213d3eb3e6f548c [file] [log] [blame]
// 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.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.BuiltinProvider;
import com.google.devtools.build.lib.packages.NativeInfo;
import com.google.devtools.build.lib.rules.cpp.LibraryToLinkWrapper.CcLinkingContext;
import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcInfoApi;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Runtime;
import java.util.Collection;
import javax.annotation.Nullable;
/** Provider for C++ compilation and linking information. */
@Immutable
public final class CcInfo extends NativeInfo implements CcInfoApi {
public static final Provider PROVIDER = new Provider();
public static final CcInfo EMPTY = CcInfo.builder().build();
private final CcCompilationContext ccCompilationContext;
// TODO(b/117875295): Rename CcLinkingInfo to CcLinkingContext
private final CcLinkingInfo ccLinkingInfo;
public CcInfo(CcCompilationContext ccCompilationContext, CcLinkingInfo ccLinkingInfo) {
super(PROVIDER);
this.ccCompilationContext = ccCompilationContext;
this.ccLinkingInfo = ccLinkingInfo;
}
@Override
public CcCompilationContext getCcCompilationContext() {
return ccCompilationContext;
}
@Override
public CcLinkingInfo getCcLinkingInfo() {
return ccLinkingInfo;
}
public static CcInfo merge(Collection<CcInfo> ccInfos) {
ImmutableList.Builder<CcCompilationContext> ccCompilationContexts = ImmutableList.builder();
ImmutableList.Builder<CcLinkingInfo> ccLinkingInfos = ImmutableList.builder();
for (CcInfo ccInfo : ccInfos) {
ccCompilationContexts.add(ccInfo.getCcCompilationContext());
ccLinkingInfos.add(ccInfo.getCcLinkingInfo());
}
CcCompilationContext.Builder builder =
new CcCompilationContext.Builder(/* ruleContext= */ null);
return new CcInfo(
builder.mergeDependentCcCompilationContexts(ccCompilationContexts.build()).build(),
CcLinkingInfo.merge(ccLinkingInfos.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.ccLinkingInfo.equals(other.ccLinkingInfo)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return Objects.hashCode(ccCompilationContext, ccLinkingInfo);
}
public static Builder builder() {
return new Builder();
}
/** A Builder for {@link CcInfo}. */
public static class Builder {
private CcCompilationContext ccCompilationContext;
private CcLinkingInfo ccLinkingInfo;
public CcInfo.Builder setCcCompilationContext(CcCompilationContext ccCompilationContext) {
Preconditions.checkState(this.ccCompilationContext == null);
this.ccCompilationContext = ccCompilationContext;
return this;
}
public CcInfo.Builder setCcLinkingInfo(CcLinkingInfo ccLinkingInfo) {
Preconditions.checkState(this.ccLinkingInfo == null);
this.ccLinkingInfo = ccLinkingInfo;
return this;
}
public CcInfo build() {
if (ccCompilationContext == null) {
ccCompilationContext = CcCompilationContext.EMPTY;
}
if (ccLinkingInfo == null) {
ccLinkingInfo = CcLinkingInfo.EMPTY;
}
return new CcInfo(ccCompilationContext, ccLinkingInfo);
}
}
/** Provider class for {@link CcInfo} objects. */
public static class Provider extends BuiltinProvider<CcInfo> implements CcInfoApi.Provider {
private Provider() {
super(CcInfoApi.NAME, CcInfo.class);
}
@Override
public CcInfoApi createInfo(
Object skylarkCcCompilationContext,
Object skylarkCcLinkingInfo,
Location location,
Environment environment)
throws EvalException {
CcCommon.checkLocationWhitelisted(
environment.getSemantics(),
location,
environment.getGlobals().getLabel().getPackageIdentifier().toString());
CcCompilationContext ccCompilationContext =
nullIfNone(skylarkCcCompilationContext, CcCompilationContext.class);
CcLinkingInfo ccLinkingInfo = null;
try {
ccLinkingInfo = nullIfNone(skylarkCcLinkingInfo, CcLinkingInfo.class);
} catch (ClassCastException e) {
// TODO(b/118663806): Eventually only CcLinkingContext will be allowed, this is for
// backwards compatibility.
CcLinkingContext ccLinkingContext =
nullIfNone(skylarkCcLinkingInfo, CcLinkingContext.class);
if (ccLinkingContext != null) {
ccLinkingInfo = ccLinkingContext.toCcLinkingInfo();
}
}
CcInfo.Builder ccInfoBuilder = CcInfo.builder();
if (ccCompilationContext != null) {
ccInfoBuilder.setCcCompilationContext(ccCompilationContext);
}
if (ccLinkingInfo != null) {
ccInfoBuilder.setCcLinkingInfo(ccLinkingInfo);
}
return ccInfoBuilder.build();
}
@Nullable
private static <T> T nullIfNone(Object object, Class<T> type) {
return object != Runtime.NONE ? type.cast(object) : null;
}
}
}