Point symlinks to headers with stripped prefix to exec root instead of source location.
Use the exec root location as the target for symlinks created for headers with stripped prefix to make sure the paths stay in sync with exec root, which could change across builds. If the header itself stays the same, then the symlink will not be updated, leading to different resolved path for the 2 paths.
PiperOrigin-RevId: 446709489
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java
index 076b956..ec0cb0b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java
@@ -69,6 +69,11 @@
private final TargetType targetType;
+ public static SymlinkAction toArtifact(
+ ActionOwner owner, Artifact input, Artifact output, String progressMessage) {
+ return toArtifact(owner, input, output, progressMessage, /*useExecRootForSource=*/ false);
+ }
+
/**
* Creates an action that creates a symlink pointing to an artifact.
*
@@ -76,10 +81,24 @@
* @param input the {@link Artifact} the symlink will point to
* @param output the {@link Artifact} that will be created by executing this Action.
* @param progressMessage the progress message.
+ * @param useExecRootForSource whether to link source artifacts to exec root as opposed to the
+ * artifact itself. This indirection makes sure that the symlink is always in sync with exec
+ * root, which could go out of sync with it when re-planting the symlink tree and the header
+ * was unchanged.
*/
- public static SymlinkAction toArtifact(ActionOwner owner, Artifact input, Artifact output,
- String progressMessage) {
- return new SymlinkAction(owner, null, input, output, progressMessage, TargetType.OTHER);
+ public static SymlinkAction toArtifact(
+ ActionOwner owner,
+ Artifact input,
+ Artifact output,
+ String progressMessage,
+ boolean useExecRootForSource) {
+ return new SymlinkAction(
+ owner,
+ useExecRootForSource && input.isSourceArtifact() ? input.getExecPath() : null,
+ input,
+ output,
+ progressMessage,
+ TargetType.OTHER);
}
public static SymlinkAction toExecutable(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
index 7582a23..17af008 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
@@ -982,7 +982,8 @@
actionConstructionContext.getActionOwner(),
originalHeader,
virtualHeader,
- "Symlinking virtual headers for " + label));
+ "Symlinking virtual headers for " + label,
+ /*useExecRootForSource=*/ true));
moduleHeadersBuilder.add(virtualHeader);
if (configuration.isCodeCoverageEnabled()) {
virtualToOriginalHeaders.add(
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java
index d5bad3a..1c72e3d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/SymlinkActionTest.java
@@ -33,21 +33,21 @@
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
import com.google.devtools.build.lib.testutil.TestConstants;
import com.google.devtools.build.lib.vfs.FileSystem;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.SyscallCache;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-/**
- * Tests {@link SymlinkAction}.
- */
-@RunWith(JUnit4.class)
+/** Tests {@link SymlinkAction}. */
+@RunWith(TestParameterInjector.class)
public class SymlinkActionTest extends BuildViewTestCase {
+ @TestParameter private boolean useExecRootForSources;
+
private Path input;
private Artifact inputArtifact;
private Path output;
@@ -60,14 +60,19 @@
inputArtifact = getSourceArtifact("input.txt");
Path linkedInput =
directories.getExecRoot(TestConstants.WORKSPACE_NAME).getRelative("input.txt");
- FileSystemUtils.createDirectoryAndParents(linkedInput.getParentDirectory());
+ linkedInput.getParentDirectory().createDirectoryAndParents();
linkedInput.createSymbolicLink(input);
outputArtifact = getBinArtifactWithNoOwner("destination.txt");
outputArtifact.setGeneratingActionKey(ActionsTestUtil.NULL_ACTION_LOOKUP_DATA);
output = outputArtifact.getPath();
- FileSystemUtils.createDirectoryAndParents(output.getParentDirectory());
- action = SymlinkAction.toArtifact(NULL_ACTION_OWNER,
- inputArtifact, outputArtifact, "Symlinking test");
+ output.getParentDirectory().createDirectoryAndParents();
+ action =
+ SymlinkAction.toArtifact(
+ NULL_ACTION_OWNER,
+ inputArtifact,
+ outputArtifact,
+ "Symlinking test",
+ useExecRootForSources);
}
@Test