/* * Copyright 2014-present Facebook, Inc. * * 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.facebook.buck.cxx; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.parser.NoSuchBuildTargetException; import com.facebook.buck.rules.AbstractBuildRule; import com.facebook.buck.rules.BinaryBuildRule; import com.facebook.buck.rules.BuildContext; import com.facebook.buck.rules.BuildRule; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.BuildableContext; import com.facebook.buck.rules.ForwardingBuildTargetSourcePath; import com.facebook.buck.rules.HasRuntimeDeps; import com.facebook.buck.rules.SourcePath; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.Tool; import com.facebook.buck.rules.coercer.FrameworkPath; import com.facebook.buck.rules.keys.SupportsInputBasedRuleKey; import com.facebook.buck.step.Step; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import java.util.stream.Stream; public class CxxBinary extends AbstractBuildRule implements BinaryBuildRule, NativeTestable, HasRuntimeDeps, ProvidesLinkedBinaryDeps, SupportsInputBasedRuleKey { private final BuildRuleParams params; private final BuildRuleResolver ruleResolver; private final SourcePathRuleFinder ruleFinder; private final CxxPlatform cxxPlatform; private final BuildRule linkRule; private final Tool executable; private final ImmutableSortedSet<BuildTarget> tests; private final ImmutableSortedSet<FrameworkPath> frameworks; private final BuildTarget platformlessTarget; public CxxBinary( BuildRuleParams params, BuildRuleResolver ruleResolver, SourcePathRuleFinder ruleFinder, CxxPlatform cxxPlatform, BuildRule linkRule, Tool executable, Iterable<FrameworkPath> frameworks, Iterable<BuildTarget> tests, BuildTarget platformlessTarget) { super(params); this.params = params; this.ruleResolver = ruleResolver; this.ruleFinder = ruleFinder; this.cxxPlatform = cxxPlatform; this.linkRule = linkRule; this.executable = executable; this.tests = ImmutableSortedSet.copyOf(tests); this.frameworks = ImmutableSortedSet.copyOf(frameworks); this.platformlessTarget = platformlessTarget; performChecks(); } private void performChecks() { Preconditions.checkArgument( linkRule instanceof CxxLink || linkRule instanceof CxxStrip, "CxxBinary (%s) link rule (%s) is expected to be instance of either CxxLink or CxxStrip", this, linkRule); Preconditions.checkArgument( getBuildDeps().contains(linkRule), "CxxBinary (%s) must depend on its link rule (%s) via deps", this, linkRule); Preconditions.checkArgument( !params.getBuildTarget().getFlavors().contains(CxxStrip.RULE_FLAVOR), "CxxBinary (%s) build target should not contain CxxStrip rule flavor %s. Otherwise " + "it may be not possible to distinguish CxxBinary (%s) and link rule (%s) in graph.", this, CxxStrip.RULE_FLAVOR, this, linkRule); Preconditions.checkArgument( this.platformlessTarget .getUnflavoredBuildTarget() .equals(this.params.getBuildTarget().getUnflavoredBuildTarget())); } @Override public Tool getExecutableCommand() { return executable; } @Override public ImmutableList<Step> getBuildSteps( BuildContext context, BuildableContext buildableContext) { return ImmutableList.of(); } @Override public SourcePath getSourcePathToOutput() { return new ForwardingBuildTargetSourcePath( getBuildTarget(), Preconditions.checkNotNull(linkRule.getSourcePathToOutput())); } public BuildRule getLinkRule() { return linkRule; } @Override public boolean isTestedBy(BuildTarget testRule) { return tests.contains(testRule); } @Override public CxxPreprocessorInput getCxxPreprocessorInput( CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) throws NoSuchBuildTargetException { return CxxPreprocessables.getCxxPreprocessorInput( params.withBuildTarget(platformlessTarget), ruleResolver, /* hasHeaderSymlinkTree */ true, cxxPlatform, headerVisibility, CxxPreprocessables.IncludeType.LOCAL, ImmutableMultimap.of(), frameworks); } @Override public ImmutableSet<BuildRule> getStaticLibraryDeps() { if (linkRule instanceof ProvidesLinkedBinaryDeps) { return ((ProvidesLinkedBinaryDeps) linkRule).getStaticLibraryDeps(); } else { return ImmutableSet.of(); } } @Override public ImmutableSet<BuildRule> getCompileDeps() { if (linkRule instanceof ProvidesLinkedBinaryDeps) { return ((ProvidesLinkedBinaryDeps) linkRule).getCompileDeps(); } else { return ImmutableSet.of(); } } // This rule just delegates to the output of the `CxxLink` rule and so needs that available at // runtime. Model this via `HasRuntimeDeps`. @Override public Stream<BuildTarget> getRuntimeDeps() { return Stream.concat(getDeclaredDeps().stream(), executable.getDeps(ruleFinder).stream()) .map(BuildRule::getBuildTarget); } public CxxPlatform getCxxPlatform() { return cxxPlatform; } }