/*
* Copyright 2016-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.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.facebook.buck.file.ProjectFilesystemMatchers;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.testutil.integration.BuckBuildLog;
import com.facebook.buck.testutil.integration.ProjectWorkspace;
import com.facebook.buck.testutil.integration.TemporaryPaths;
import com.facebook.buck.testutil.integration.TestDataHelper;
import com.facebook.buck.util.environment.Platform;
import java.io.IOException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
public class PrecompiledHeaderIntegrationTest {
private ProjectWorkspace workspace;
@Rule public TemporaryPaths tmp = new TemporaryPaths();
@Before
public void setUp() throws IOException {
workspace = TestDataHelper.createProjectWorkspaceForScenario(this, "precompiled_headers", tmp);
workspace.setUp();
}
@Test
public void compilesWithPrecompiledHeaders() throws IOException {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.runBuckBuild("//:some_library#default,static").assertSuccess();
findPchTarget();
}
@Test
public void pchDepFileHasReferencedHeaders() throws IOException {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.runBuckBuild("//:some_library#default,static").assertSuccess();
BuildTarget target = findPchTarget();
String depFileContents =
workspace.getFileContents(
"buck-out/gen/" + target.getShortNameAndFlavorPostfix() + ".h.gch.dep");
assertThat(depFileContents, containsString("referenced_by_prefix_header.h"));
}
@Test
public void changingPrefixHeaderCausesRecompile() throws Exception {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
workspace.resetBuildLogFile();
workspace.writeContentsToPath(
"#pragma once\n"
+ "#include <stdio.h>\n"
+ "#include \"referenced_by_prefix_header.h\"\n"
+ "#include <referenced_by_prefix_header_from_dependency.h>\n"
+ "#define FOO 100\n",
"prefix_header.h");
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
buildLog.assertTargetBuiltLocally(findPchTarget().toString());
buildLog.assertTargetBuiltLocally("//:some_library#default,static");
}
@Test
public void changingPchReferencedHeaderFromSameTargetCausesLibraryToRecompile() throws Exception {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
workspace.resetBuildLogFile();
workspace.writeContentsToPath(
"#pragma once\n#define REFERENCED_BY_PREFIX_HEADER 3\n", "referenced_by_prefix_header.h");
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
buildLog.assertTargetBuiltLocally(findPchTarget().toString());
buildLog.assertTargetBuiltLocally("//:some_library#default,static");
}
@Test
public void changingPchReferencedHeaderFromDependencyCausesLibraryToRecompile() throws Exception {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
workspace.resetBuildLogFile();
workspace.writeContentsToPath(
"#pragma once\n#define REFERENCED_BY_PREFIX_HEADER_FROM_DEPENDENCY 3\n",
"referenced_by_prefix_header_from_dependency.h");
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
buildLog.assertTargetBuiltLocally(findPchTarget().toString());
buildLog.assertTargetBuiltLocally("//:some_library#default,static");
}
@Test
public void touchingPchReferencedHeaderShouldNotCauseClangToRejectPch() throws Exception {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
workspace.resetBuildLogFile();
// Change this file (not in the pch) to trigger recompile.
workspace.writeContentsToPath("int lib_func() { return 0; }", "lib.c");
// Touch this file that contributes to the PCH without changing its contents.
workspace.writeContentsToPath(
workspace.getFileContents("referenced_by_prefix_header_from_dependency.h"),
"referenced_by_prefix_header_from_dependency.h");
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
buildLog.assertTargetHadMatchingRuleKey(findPchTarget().toString());
buildLog.assertTargetBuiltLocally("//:some_library#default,static");
}
@Test
public void changingCodeUsingPchWhenPchIsCachedButNotBuiltShouldBuildPch() throws Exception {
assumeTrue(Platform.detect() != Platform.WINDOWS);
workspace.enableDirCache();
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
workspace.runBuckCommand("clean");
workspace.writeContentsToPath("int lib_func() { return 0; }", "lib.c");
workspace.runBuckBuild("//:some_binary#default").assertSuccess();
BuckBuildLog buildLog = workspace.getBuildLog();
buildLog.assertTargetBuiltLocally(findPchTarget().toString());
assertThat(
workspace.asCell().getFilesystem(),
ProjectFilesystemMatchers.pathExists(
workspace.getPath(
"buck-out/gen/" + findPchTarget().getShortNameAndFlavorPostfix() + ".h.gch")));
buildLog.assertTargetBuiltLocally("//:some_library#default,static");
}
private BuildTarget findPchTarget() throws IOException {
for (BuildTarget target : workspace.getBuildLog().getAllTargets()) {
for (Flavor flavor : target.getFlavors()) {
if (flavor.getName().startsWith("pch-")) {
return target;
}
}
}
fail("should have generated a pch target");
return null;
}
}