| /* |
| * 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 static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| |
| import com.facebook.buck.android.AndroidPackageable; |
| import com.facebook.buck.android.AndroidPackageableCollector; |
| import com.facebook.buck.io.ProjectFilesystem; |
| import com.facebook.buck.model.BuildTarget; |
| import com.facebook.buck.model.BuildTargetFactory; |
| import com.facebook.buck.model.HasBuildTarget; |
| import com.facebook.buck.python.ImmutablePythonPackageComponents; |
| import com.facebook.buck.python.PythonPackageComponents; |
| import com.facebook.buck.rules.BuildRule; |
| import com.facebook.buck.rules.BuildRuleParams; |
| import com.facebook.buck.rules.BuildRuleParamsFactory; |
| import com.facebook.buck.rules.BuildRuleResolver; |
| import com.facebook.buck.rules.BuildTargetSourcePath; |
| import com.facebook.buck.rules.FakeBuildRule; |
| import com.facebook.buck.rules.FakeBuildRuleParamsBuilder; |
| import com.facebook.buck.rules.SourcePath; |
| import com.facebook.buck.rules.SourcePathResolver; |
| import com.facebook.buck.rules.TestSourcePath; |
| import com.facebook.buck.rules.coercer.SourceWithFlags; |
| import com.facebook.buck.shell.Genrule; |
| import com.facebook.buck.shell.GenruleBuilder; |
| import com.facebook.buck.testutil.FakeProjectFilesystem; |
| import com.google.common.collect.FluentIterable; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.ImmutableSortedSet; |
| |
| import org.junit.Test; |
| |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| |
| public class CxxBinaryDescriptionTest { |
| |
| private static FakeBuildRule createFakeBuildRule( |
| String target, |
| SourcePathResolver resolver, |
| BuildRule... deps) { |
| return new FakeBuildRule( |
| new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance(target)) |
| .setDeps(ImmutableSortedSet.copyOf(deps)) |
| .build(), |
| resolver); |
| } |
| |
| @Test |
| @SuppressWarnings("PMD.UseAssertTrueInsteadOfAssertEquals") |
| public void createBuildRule() { |
| ProjectFilesystem projectFilesystem = new FakeProjectFilesystem(); |
| BuildRuleResolver resolver = new BuildRuleResolver(); |
| SourcePathResolver pathResolver = new SourcePathResolver(resolver); |
| CxxPlatform cxxPlatform = CxxBinaryBuilder.createDefaultPlatform(); |
| |
| // Setup a genrule the generates a header we'll list. |
| String genHeaderName = "test/foo.h"; |
| BuildTarget genHeaderTarget = BuildTargetFactory.newInstance("//:genHeader"); |
| Genrule genHeader = (Genrule) GenruleBuilder |
| .newGenruleBuilder(genHeaderTarget) |
| .setOut(genHeaderName) |
| .build(resolver); |
| |
| // Setup a genrule the generates a source we'll list. |
| String genSourceName = "test/foo.cpp"; |
| BuildTarget genSourceTarget = BuildTargetFactory.newInstance("//:genSource"); |
| Genrule genSource = (Genrule) GenruleBuilder |
| .newGenruleBuilder(genSourceTarget) |
| .setOut(genSourceName) |
| .build(resolver); |
| |
| // Setup a C/C++ library that we'll depend on form the C/C++ binary description. |
| final BuildRule header = createFakeBuildRule("//:header", pathResolver); |
| final BuildRule headerSymlinkTree = createFakeBuildRule("//:symlink", pathResolver); |
| final Path headerSymlinkTreeRoot = Paths.get("symlink/tree/root"); |
| final BuildRule archive = createFakeBuildRule("//:archive", pathResolver); |
| final Path archiveOutput = Paths.get("output/path/lib.a"); |
| BuildTarget depTarget = BuildTargetFactory.newInstance("//:dep"); |
| BuildRuleParams depParams = BuildRuleParamsFactory.createTrivialBuildRuleParams(depTarget); |
| AbstractCxxLibrary dep = new AbstractCxxLibrary(depParams, pathResolver) { |
| |
| @Override |
| public CxxPreprocessorInput getCxxPreprocessorInput(CxxPlatform cxxPlatform) { |
| return CxxPreprocessorInput.builder() |
| .addRules( |
| header.getBuildTarget(), |
| headerSymlinkTree.getBuildTarget()) |
| .addIncludeRoots(headerSymlinkTreeRoot) |
| .build(); |
| } |
| |
| @Override |
| public NativeLinkableInput getNativeLinkableInput( |
| CxxPlatform cxxPlatform, |
| Linker.LinkableDepType type) { |
| return ImmutableNativeLinkableInput.of( |
| ImmutableList.<SourcePath>of( |
| new BuildTargetSourcePath(getProjectFilesystem(), archive.getBuildTarget())), |
| ImmutableList.of(archiveOutput.toString())); |
| } |
| |
| @Override |
| public PythonPackageComponents getPythonPackageComponents(CxxPlatform cxxPlatform) { |
| return ImmutablePythonPackageComponents.of( |
| ImmutableMap.<Path, SourcePath>of(), |
| ImmutableMap.<Path, SourcePath>of(), |
| ImmutableMap.<Path, SourcePath>of()); |
| } |
| |
| @Override |
| public Iterable<AndroidPackageable> getRequiredPackageables() { |
| return ImmutableList.of(); |
| } |
| |
| @Override |
| public void addToCollector(AndroidPackageableCollector collector) {} |
| |
| @Override |
| public ImmutableMap<String, SourcePath> getSharedLibraries(CxxPlatform cxxPlatform) { |
| return ImmutableMap.of(); |
| } |
| |
| }; |
| resolver.addAllToIndex(ImmutableList.of(header, headerSymlinkTree, archive, dep)); |
| |
| // Setup the build params we'll pass to description when generating the build rules. |
| BuildTarget target = BuildTargetFactory.newInstance("//:rule"); |
| CxxBinary binRule = (CxxBinary) new CxxBinaryBuilder(target) |
| .setSrcs( |
| ImmutableList.of( |
| SourceWithFlags.of(new TestSourcePath("test/bar.cpp")), |
| SourceWithFlags.of( |
| new BuildTargetSourcePath(projectFilesystem, genSource.getBuildTarget())))) |
| .setHeaders( |
| ImmutableList.<SourcePath>of( |
| new TestSourcePath("test/bar.h"), |
| new BuildTargetSourcePath(projectFilesystem, genHeader.getBuildTarget()))) |
| .setDeps(ImmutableSortedSet.of(dep.getBuildTarget())) |
| .build(resolver); |
| CxxLink rule = binRule.getRule(); |
| |
| // Check that link rule has the expected deps: the object files for our sources and the |
| // archive from the dependency. |
| assertEquals( |
| ImmutableSet.of( |
| CxxCompilableEnhancer.createCompileBuildTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| "test/bar.cpp", |
| /* pic */ false), |
| CxxCompilableEnhancer.createCompileBuildTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| genSourceName, |
| /* pic */ false), |
| archive.getBuildTarget()), |
| FluentIterable.from(rule.getDeps()) |
| .transform(HasBuildTarget.TO_TARGET) |
| .toSet()); |
| |
| // Verify that the preproces rule for our user-provided source has correct deps setup |
| // for the various header rules. |
| BuildRule preprocessRule1 = resolver.getRule( |
| CxxPreprocessables.createPreprocessBuildTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| CxxSource.Type.CXX, |
| /* pic */ false, |
| "test/bar.cpp")); |
| assertEquals( |
| ImmutableSet.of( |
| genHeaderTarget, |
| headerSymlinkTree.getBuildTarget(), |
| header.getBuildTarget(), |
| CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| CxxDescriptionEnhancer.HeaderVisibility.PRIVATE)), |
| FluentIterable.from(preprocessRule1.getDeps()) |
| .transform(HasBuildTarget.TO_TARGET) |
| .toSet()); |
| |
| // Verify that the compile rule for our user-provided source has correct deps setup |
| // for the various header rules. |
| BuildRule compileRule1 = resolver.getRule( |
| CxxCompilableEnhancer.createCompileBuildTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| "test/bar.cpp", |
| /* pic */ false)); |
| assertNotNull(compileRule1); |
| assertEquals( |
| ImmutableSet.of( |
| preprocessRule1.getBuildTarget()), |
| FluentIterable.from(compileRule1.getDeps()) |
| .transform(HasBuildTarget.TO_TARGET) |
| .toSet()); |
| |
| // Verify that the preproces rule for our user-provided source has correct deps setup |
| // for the various header rules. |
| BuildRule preprocessRule2 = resolver.getRule( |
| CxxPreprocessables.createPreprocessBuildTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| CxxSource.Type.CXX, |
| /* pic */ false, |
| genSourceName)); |
| assertEquals( |
| ImmutableSet.of( |
| genHeaderTarget, |
| genSourceTarget, |
| headerSymlinkTree.getBuildTarget(), |
| header.getBuildTarget(), |
| CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| CxxDescriptionEnhancer.HeaderVisibility.PRIVATE)), |
| FluentIterable.from(preprocessRule2.getDeps()) |
| .transform(HasBuildTarget.TO_TARGET) |
| .toSet()); |
| |
| // Verify that the compile rule for our genrule-generated source has correct deps setup |
| // for the various header rules and the generating genrule. |
| BuildRule compileRule2 = resolver.getRule( |
| CxxCompilableEnhancer.createCompileBuildTarget( |
| target, |
| cxxPlatform.getFlavor(), |
| genSourceName, |
| /* pic */ false)); |
| assertNotNull(compileRule2); |
| assertEquals( |
| ImmutableSet.of( |
| preprocessRule2.getBuildTarget()), |
| FluentIterable.from(compileRule2.getDeps()) |
| .transform(HasBuildTarget.TO_TARGET) |
| .toSet()); |
| } |
| |
| } |