Skip to content

Commit

Permalink
Add the runfiles directory to the runtime library search paths
Browse files Browse the repository at this point in the history
When executing a C++ binary through REv2 directly (e.g., directly as a
genrule, not as a dependency of another script/executable), the input
root will only contain a _solib_arch directory inside the executable's
runfiles directory. This means that library lookups also need to
consider rpath $ORIGIN/$executable.runfiles/$workspace/_solib_$arch/.
Only looking at ../../../_solib_$arch/ is not sufficient.

This issue isn't noticeable when doing local execution, for the reason
that rtld/dyld will first do a realpath() on the executable, meaning the
lookup of shared objects takes place outside of the sandbox, inside of
bazel-out/ directly.

This change extends LibrariesToLinkCollector to duplicate all runtime
library search paths. One for bare execution, and one for execution
inside a runfiles directory.
  • Loading branch information
EdSchouten committed Jan 19, 2022
1 parent 788ff3e commit 4d9e0ca
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.devtools.build.lib.actions.ActionOwner;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ParameterFile;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.RuleErrorConsumer;
import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext;
import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
Expand Down Expand Up @@ -798,7 +799,8 @@ public CppLinkAction build() throws InterruptedException, RuleErrorException {
allowLtoIndexing,
nonExpandedLinkerInputs,
needWholeArchive,
ruleErrorConsumer);
ruleErrorConsumer,
((RuleContext) actionConstructionContext).getWorkspaceName());
CollectedLibrariesToLink collectedLibrariesToLink =
librariesToLinkCollector.collectLibrariesToLink();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class LibrariesToLinkCollector {
private final Artifact thinltoParamFile;
private final FeatureConfiguration featureConfiguration;
private final boolean needWholeArchive;
private final String rpathRoot;
private final ImmutableList<String> rpathRoots;
private final boolean needToolchainLibrariesRpath;
private final Map<Artifact, Artifact> ltoMap;
private final RuleErrorConsumer ruleErrorConsumer;
Expand All @@ -68,7 +68,8 @@ public LibrariesToLinkCollector(
boolean allowLtoIndexing,
Iterable<LinkerInput> linkerInputs,
boolean needWholeArchive,
RuleErrorConsumer ruleErrorConsumer) {
RuleErrorConsumer ruleErrorConsumer,
String workspaceName) {
this.isNativeDeps = isNativeDeps;
this.cppConfiguration = cppConfiguration;
this.ccToolchainProvider = toolchain;
Expand Down Expand Up @@ -103,12 +104,25 @@ public LibrariesToLinkCollector(
// and the second could use $ORIGIN/../_solib_[arch]. But since this is a shared
// artifact, both are symlinks to the same place, so
// there's no *one* RPATH setting that fits all targets involved in the sharing.
rpathRoot = ccToolchainProvider.getSolibDirectory() + "/";
rpathRoots = ImmutableList.of(ccToolchainProvider.getSolibDirectory() + "/");
} else {
rpathRoot =
"../".repeat(outputArtifact.getRootRelativePath().segmentCount() - 1)
+ ccToolchainProvider.getSolibDirectory()
+ "/";
// When the binary gets run through remote execution as the main executable (i.e., not as a
// dependency of another target), it will not be able to find its libraries at
// $ORIGIN/../../../_solib_[arch], as execution is not taking place inside the runfiles
// directory. Solve this by adding ${executable}.runfiles/${workspace}/_solib_[arch] as an
// rpath root.
PathFragment rootRelativePath = outputArtifact.getRootRelativePath();
String solibDirectory = ccToolchainProvider.getSolibDirectory();
rpathRoots = ImmutableList.of(
rootRelativePath.getBaseName()
+ ".runfiles/"
+ workspaceName
+ "/"
+ solibDirectory
+ "/",
"../".repeat(rootRelativePath.segmentCount() - 1)
+ solibDirectory
+ "/");
}

ltoMap = generateLtoMap();
Expand Down Expand Up @@ -183,10 +197,7 @@ public CollectedLibrariesToLink collectLibrariesToLink() {
// directory. In other words, given blaze-bin/my/package/binary, rpathRoot would be
// "../../_solib_[arch]".
if (needToolchainLibrariesRpath) {
runtimeLibrarySearchDirectories.add(
"../".repeat(outputArtifact.getRootRelativePath().segmentCount() - 1)
+ toolchainLibrariesSolibName
+ "/");
runtimeLibrarySearchDirectories.addAll(rpathRoots);
}
if (isNativeDeps) {
// We also retain the $ORIGIN/ path to solibs that are in _solib_<arch>, as opposed to
Expand Down Expand Up @@ -218,7 +229,7 @@ public CollectedLibrariesToLink collectLibrariesToLink() {
NestedSetBuilder<String> allRuntimeLibrarySearchDirectories = NestedSetBuilder.linkOrder();
// rpath ordering matters for performance; first add the one where most libraries are found.
if (includeSolibDir) {
allRuntimeLibrarySearchDirectories.add(rpathRoot);
allRuntimeLibrarySearchDirectories.addAll(rpathRoots);
}
allRuntimeLibrarySearchDirectories.addAll(rpathRootsForExplicitSoDeps.build());
if (includeToolchainLibrariesSolibDir) {
Expand Down Expand Up @@ -330,8 +341,10 @@ private void addDynamicInputLinkOptions(
commonParent = commonParent.getParentDirectory();
}

rpathRootsForExplicitSoDeps.add(
rpathRoot + dotdots + libDir.relativeTo(commonParent).getPathString());
for (String rpathRoot : rpathRoots) {
rpathRootsForExplicitSoDeps.add(
rpathRoot + dotdots + libDir.relativeTo(commonParent).getPathString());
}
}

librarySearchDirectories.add(inputArtifact.getExecPath().getParentDirectory().getPathString());
Expand Down

0 comments on commit 4d9e0ca

Please sign in to comment.