| /* |
| * 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.assertTrue; |
| |
| import com.facebook.buck.android.AndroidPackageable; |
| import com.facebook.buck.android.AndroidPackageableCollector; |
| import com.facebook.buck.cli.FakeBuckConfig; |
| import com.facebook.buck.io.ProjectFilesystem; |
| import com.facebook.buck.model.BuildTarget; |
| import com.facebook.buck.model.BuildTargetFactory; |
| import com.facebook.buck.model.FlavorDomain; |
| 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.PathSourcePath; |
| import com.facebook.buck.rules.SourcePath; |
| import com.facebook.buck.rules.SourcePathResolver; |
| import com.facebook.buck.shell.GenruleBuilder; |
| import com.facebook.buck.testutil.FakeProjectFilesystem; |
| import com.facebook.buck.testutil.TargetGraphFactory; |
| import com.google.common.base.Optional; |
| 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 com.google.common.collect.Iterables; |
| |
| import org.junit.Test; |
| |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.Map; |
| |
| public class CxxPythonExtensionDescriptionTest { |
| |
| private static final BuildTarget PYTHON_DEP_TARGET = |
| BuildTargetFactory.newInstance("//:python_dep"); |
| |
| private static FakeBuildRule createFakeBuildRule( |
| String target, |
| SourcePathResolver resolver, |
| BuildRule... deps) { |
| return new FakeBuildRule( |
| new FakeBuildRuleParamsBuilder(BuildTargetFactory.newInstance(target)) |
| .setDeps(ImmutableSortedSet.copyOf(deps)) |
| .build(), resolver); |
| } |
| |
| public CxxPythonExtensionBuilder getBuilder(BuildTarget target) { |
| FakeBuckConfig buckConfig = new FakeBuckConfig( |
| ImmutableMap.<String, Map<String, String>>of( |
| "cxx", ImmutableMap.of( |
| "python_dep", PYTHON_DEP_TARGET.toString()))); |
| CxxBuckConfig cxxBuckConfig = new CxxBuckConfig(buckConfig); |
| FlavorDomain<CxxPlatform> cxxPlatforms = CxxPythonExtensionBuilder.createDefaultPlatforms(); |
| return new CxxPythonExtensionBuilder(target, cxxBuckConfig, cxxPlatforms); |
| } |
| |
| @Test |
| public void createBuildRuleBaseModule() { |
| BuildTarget target = BuildTargetFactory.newInstance("//:target"); |
| ProjectFilesystem filesystem = new FakeProjectFilesystem(); |
| CxxPlatform cxxPlatform = CxxPythonExtensionBuilder.createDefaultPlatform(); |
| |
| // Verify we use the default base module when none is set. |
| CxxPythonExtensionBuilder normalBuilder = getBuilder(target); |
| CxxPythonExtensionDescription desc = |
| (CxxPythonExtensionDescription) normalBuilder.build().getDescription(); |
| CxxPythonExtension normal = (CxxPythonExtension) normalBuilder |
| .build( |
| new BuildRuleResolver(), |
| filesystem, |
| TargetGraphFactory.newInstance( |
| normalBuilder.build(), |
| GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build())); |
| PythonPackageComponents normalComps = normal.getPythonPackageComponents(cxxPlatform); |
| assertEquals( |
| ImmutableSet.of( |
| target.getBasePath().resolve(desc.getExtensionName(target))), |
| normalComps.getModules().keySet()); |
| |
| // Verify that explicitly setting works. |
| String name = "blah"; |
| CxxPythonExtensionBuilder baseModuleBuilder = getBuilder(target) |
| .setBaseModule(name); |
| desc = (CxxPythonExtensionDescription) baseModuleBuilder.build().getDescription(); |
| CxxPythonExtension baseModule = (CxxPythonExtension) baseModuleBuilder |
| .build( |
| new BuildRuleResolver(), |
| filesystem, |
| TargetGraphFactory.newInstance( |
| baseModuleBuilder.build(), |
| GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build())); |
| PythonPackageComponents baseModuleComps = baseModule.getPythonPackageComponents(cxxPlatform); |
| assertEquals( |
| ImmutableSet.of( |
| Paths.get(name).resolve(desc.getExtensionName(target))), |
| baseModuleComps.getModules().keySet()); |
| } |
| |
| @Test |
| public void createBuildRuleNativeLinkableDep() { |
| BuildTarget target = BuildTargetFactory.newInstance("//:target"); |
| BuildRuleResolver resolver = new BuildRuleResolver(); |
| SourcePathResolver pathResolver = new SourcePathResolver(resolver); |
| CxxPlatform cxxPlatform = CxxPythonExtensionBuilder.createDefaultPlatform(); |
| |
| // Setup a C/C++ library that we'll depend on form the C/C++ binary description. |
| final BuildRule sharedLibraryDep = createFakeBuildRule("//:shared", pathResolver); |
| final Path sharedLibraryOutput = Paths.get("output/path/lib.so"); |
| final String sharedLibrarySoname = "soname"; |
| BuildTarget depTarget = BuildTargetFactory.newInstance("//:dep"); |
| BuildRuleParams depParams = BuildRuleParamsFactory.createTrivialBuildRuleParams(depTarget); |
| AbstractCxxLibrary dep = new AbstractCxxLibrary(depParams, pathResolver) { |
| |
| @Override |
| public CxxPreprocessorInput getCxxPreprocessorInput(CxxPlatform cxxPlatform) { |
| return CxxPreprocessorInput.EMPTY; |
| } |
| |
| @Override |
| public NativeLinkableInput getNativeLinkableInput( |
| CxxPlatform cxxPlatform, |
| Linker.LinkableDepType type) { |
| return type == Linker.LinkableDepType.STATIC ? |
| ImmutableNativeLinkableInput.of( |
| ImmutableList.<SourcePath>of(), |
| ImmutableList.<String>of()) : |
| ImmutableNativeLinkableInput.of( |
| ImmutableList.<SourcePath>of( |
| new BuildTargetSourcePath( |
| getProjectFilesystem(), |
| sharedLibraryDep.getBuildTarget(), |
| sharedLibraryOutput)), |
| ImmutableList.of(sharedLibraryOutput.toString())); |
| } |
| |
| @Override |
| public PythonPackageComponents getPythonPackageComponents(CxxPlatform cxxPlatform) { |
| return ImmutablePythonPackageComponents.of( |
| ImmutableMap.<Path, SourcePath>of(), |
| ImmutableMap.<Path, SourcePath>of(), |
| ImmutableMap.<Path, SourcePath>of( |
| Paths.get(sharedLibrarySoname), |
| new PathSourcePath(getProjectFilesystem(), sharedLibraryOutput))); |
| } |
| |
| @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(sharedLibraryDep, dep)); |
| |
| // Create args with the above dep set and create the python extension. |
| CxxPythonExtensionBuilder extensionBuilder = (CxxPythonExtensionBuilder) getBuilder(target) |
| .setDeps(ImmutableSortedSet.of(depTarget)); |
| CxxPythonExtensionDescription desc = |
| (CxxPythonExtensionDescription) extensionBuilder.build().getDescription(); |
| CxxPythonExtension extension = (CxxPythonExtension) extensionBuilder.build( |
| resolver, |
| new FakeProjectFilesystem(), |
| TargetGraphFactory.newInstance( |
| extensionBuilder.build(), |
| GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build(), |
| GenruleBuilder.newGenruleBuilder(depTarget).build())); |
| |
| // Verify that the shared library dep propagated to the link rule. |
| extension.getPythonPackageComponents(cxxPlatform); |
| BuildRule rule = resolver.getRule(desc.getExtensionTarget(target, cxxPlatform.getFlavor())); |
| assertEquals( |
| ImmutableSortedSet.of(sharedLibraryDep), |
| rule.getDeps()); |
| } |
| |
| @Test |
| public void createBuildRulePythonPackageable() { |
| ProjectFilesystem projectFilesystem = new FakeProjectFilesystem(); |
| BuildTarget target = BuildTargetFactory.newInstance("//:target"); |
| BuildRuleResolver resolver = new BuildRuleResolver(); |
| CxxPlatform cxxPlatform = CxxPythonExtensionBuilder.createDefaultPlatform(); |
| CxxPythonExtensionBuilder extensionBuilder = getBuilder(target); |
| CxxPythonExtensionDescription desc = |
| (CxxPythonExtensionDescription) extensionBuilder.build().getDescription(); |
| CxxPythonExtension extension = (CxxPythonExtension) extensionBuilder.build( |
| resolver, |
| projectFilesystem, |
| TargetGraphFactory.newInstance( |
| extensionBuilder.build(), |
| GenruleBuilder.newGenruleBuilder(PYTHON_DEP_TARGET).build())); |
| |
| // Verify that we get the expected view from the python packageable interface. |
| PythonPackageComponents actualComponent = extension.getPythonPackageComponents(cxxPlatform); |
| BuildRule rule = resolver.getRule(desc.getExtensionTarget(target, cxxPlatform.getFlavor())); |
| PythonPackageComponents expectedComponents = ImmutablePythonPackageComponents.of( |
| ImmutableMap.<Path, SourcePath>of( |
| target.getBasePath().resolve(desc.getExtensionName(target)), |
| new BuildTargetSourcePath(projectFilesystem, rule.getBuildTarget())), |
| ImmutableMap.<Path, SourcePath>of(), |
| ImmutableMap.<Path, SourcePath>of()); |
| assertEquals( |
| expectedComponents, |
| actualComponent); |
| } |
| |
| @Test |
| public void findDepsFromParamsAddsPythonDep() { |
| BuildTarget target = BuildTargetFactory.newInstance("//:target"); |
| CxxPythonExtensionDescription desc = |
| (CxxPythonExtensionDescription) getBuilder(target).build().getDescription(); |
| CxxPythonExtensionDescription.Arg constructorArg = desc.createUnpopulatedConstructorArg(); |
| constructorArg.lexSrcs = Optional.of(ImmutableList.<SourcePath>of()); |
| Iterable<BuildTarget> res = desc.findDepsForTargetFromConstructorArgs( |
| BuildTargetFactory.newInstance("//foo:bar"), |
| constructorArg); |
| assertTrue(Iterables.contains(res, PYTHON_DEP_TARGET)); |
| } |
| |
| } |