/* * Copyright 2015-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.assertThat; import static org.junit.Assert.assertTrue; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.BuildTargetFactory; import com.facebook.buck.model.BuildTargets; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.rules.BuildRuleParams; import com.facebook.buck.rules.BuildRuleResolver; import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer; import com.facebook.buck.rules.FakeBuildContext; import com.facebook.buck.rules.FakeBuildRuleParamsBuilder; import com.facebook.buck.rules.FakeBuildableContext; import com.facebook.buck.rules.FakeSourcePath; import com.facebook.buck.rules.HashedFileTool; import com.facebook.buck.rules.RuleKeyObjectSink; import com.facebook.buck.rules.SourcePathResolver; import com.facebook.buck.rules.SourcePathRuleFinder; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.args.RuleKeyAppendableFunction; import com.facebook.buck.rules.coercer.FrameworkPath; import com.facebook.buck.step.Step; import com.facebook.buck.step.fs.MkdirStep; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.facebook.buck.testutil.MoreAsserts; import com.facebook.buck.util.MoreCollectors; 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 java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Optional; import org.hamcrest.Matchers; import org.junit.Test; public class CxxCompilationDatabaseTest { @Test public void testCompilationDatabase() throws Exception { BuildTarget testBuildTarget = BuildTarget.builder(BuildTargetFactory.newInstance("//foo:baz")) .addAllFlavors(ImmutableSet.of(CxxCompilationDatabase.COMPILATION_DATABASE)) .build(); final String root = "/Users/user/src"; final Path fakeRoot = Paths.get(root); ProjectFilesystem filesystem = new FakeProjectFilesystem(fakeRoot); BuildRuleParams testBuildRuleParams = new FakeBuildRuleParamsBuilder(testBuildTarget).setProjectFilesystem(filesystem).build(); BuildRuleResolver testBuildRuleResolver = new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()); SourcePathResolver testSourcePathResolver = new SourcePathResolver(new SourcePathRuleFinder(testBuildRuleResolver)); HeaderSymlinkTree privateSymlinkTree = CxxDescriptionEnhancer.createHeaderSymlinkTree( testBuildRuleParams, testBuildRuleResolver, CxxPlatformUtils.DEFAULT_PLATFORM, ImmutableMap.of(), HeaderVisibility.PRIVATE, true); testBuildRuleResolver.addToIndex(privateSymlinkTree); HeaderSymlinkTree exportedSymlinkTree = CxxDescriptionEnhancer.createHeaderSymlinkTree( testBuildRuleParams, testBuildRuleResolver, CxxPlatformUtils.DEFAULT_PLATFORM, ImmutableMap.of(), HeaderVisibility.PUBLIC, true); testBuildRuleResolver.addToIndex(exportedSymlinkTree); BuildTarget compileTarget = BuildTarget.builder(testBuildRuleParams.getBuildTarget().getUnflavoredBuildTarget()) .addFlavors(InternalFlavor.of("compile-test.cpp")) .build(); PreprocessorFlags preprocessorFlags = PreprocessorFlags.builder() .addIncludes( CxxHeadersDir.of( CxxPreprocessables.IncludeType.SYSTEM, new FakeSourcePath("/foo/bar")), CxxHeadersDir.of( CxxPreprocessables.IncludeType.SYSTEM, new FakeSourcePath("/test"))) .build(); ImmutableSortedSet.Builder<CxxPreprocessAndCompile> rules = ImmutableSortedSet.naturalOrder(); BuildRuleParams compileBuildRuleParams = new FakeBuildRuleParamsBuilder(compileTarget) .setProjectFilesystem(filesystem) .setDeclaredDeps(ImmutableSortedSet.of(privateSymlinkTree, exportedSymlinkTree)) .build(); rules.add( testBuildRuleResolver.addToIndex( CxxPreprocessAndCompile.preprocessAndCompile( compileBuildRuleParams, new PreprocessorDelegate( testSourcePathResolver, CxxPlatformUtils.DEFAULT_COMPILER_DEBUG_PATH_SANITIZER, CxxPlatformUtils.DEFAULT_PLATFORM.getHeaderVerification(), filesystem.getRootPath(), new GccPreprocessor(new HashedFileTool(Paths.get("preprocessor"))), preprocessorFlags, new RuleKeyAppendableFunction<FrameworkPath, Path>() { @Override public void appendToRuleKey(RuleKeyObjectSink sink) { // Do nothing. } @Override public Path apply(FrameworkPath input) { throw new UnsupportedOperationException("should not be called"); } }, Optional.empty(), /* leadingIncludePaths */ Optional.empty()), new CompilerDelegate( testSourcePathResolver, CxxPlatformUtils.DEFAULT_COMPILER_DEBUG_PATH_SANITIZER, new GccCompiler(new HashedFileTool(Paths.get("compiler"))), CxxToolFlags.of()), Paths.get("test.o"), new FakeSourcePath(filesystem, "test.cpp"), CxxSource.Type.CXX, Optional.empty(), CxxPlatformUtils.DEFAULT_COMPILER_DEBUG_PATH_SANITIZER, Optional.empty()))); CxxCompilationDatabase compilationDatabase = CxxCompilationDatabase.createCompilationDatabase(testBuildRuleParams, rules.build()); testBuildRuleResolver.addToIndex(compilationDatabase); assertThat( compilationDatabase.getRuntimeDeps().collect(MoreCollectors.toImmutableSet()), Matchers.contains( exportedSymlinkTree.getBuildTarget(), privateSymlinkTree.getBuildTarget())); assertEquals( "getPathToOutput() should be a function of the build target.", BuildTargets.getGenPath(filesystem, testBuildTarget, "__%s.json"), testSourcePathResolver.getRelativePath(compilationDatabase.getSourcePathToOutput())); List<Step> buildSteps = compilationDatabase.getBuildSteps( FakeBuildContext.withSourcePathResolver(testSourcePathResolver), new FakeBuildableContext()); assertEquals(2, buildSteps.size()); assertTrue(buildSteps.get(0) instanceof MkdirStep); assertTrue(buildSteps.get(1) instanceof CxxCompilationDatabase.GenerateCompilationCommandsJson); CxxCompilationDatabase.GenerateCompilationCommandsJson step = (CxxCompilationDatabase.GenerateCompilationCommandsJson) buildSteps.get(1); Iterable<CxxCompilationDatabaseEntry> observedEntries = step.createEntries(); Iterable<CxxCompilationDatabaseEntry> expectedEntries = ImmutableList.of( CxxCompilationDatabaseEntry.of( root, root + "/test.cpp", ImmutableList.of( "compiler", "-isystem", "/foo/bar", "-isystem", "/test", "-x", "c++", "-c", "-MD", "-MF", "test.o.dep", "test.cpp", "-o", "test.o"))); MoreAsserts.assertIterablesEquals(expectedEntries, observedEntries); } }