13
13
// limitations under the License.
14
14
package com .google .devtools .build .lib .rules .cpp ;
15
15
16
+ import static com .google .common .collect .ImmutableList .toImmutableList ;
17
+
16
18
import com .google .common .base .Preconditions ;
17
19
import com .google .common .collect .ImmutableList ;
18
20
import com .google .common .collect .ImmutableSet ;
@@ -40,7 +42,6 @@ public class LibrariesToLinkCollector {
40
42
private final PathFragment toolchainLibrariesSolibDir ;
41
43
private final CppConfiguration cppConfiguration ;
42
44
private final CcToolchainProvider ccToolchainProvider ;
43
- private final Artifact outputArtifact ;
44
45
private final boolean isLtoIndexing ;
45
46
private final PathFragment solibDir ;
46
47
private final Iterable <? extends LinkerInput > linkerInputs ;
@@ -49,7 +50,8 @@ public class LibrariesToLinkCollector {
49
50
private final Artifact thinltoParamFile ;
50
51
private final FeatureConfiguration featureConfiguration ;
51
52
private final boolean needWholeArchive ;
52
- private final String rpathRoot ;
53
+ private final ImmutableList <String > potentialExecRoots ;
54
+ private final ImmutableList <String > rpathRoots ;
53
55
private final boolean needToolchainLibrariesRpath ;
54
56
private final Map <Artifact , Artifact > ltoMap ;
55
57
private final RuleErrorConsumer ruleErrorConsumer ;
@@ -76,7 +78,6 @@ public LibrariesToLinkCollector(
76
78
this .cppConfiguration = cppConfiguration ;
77
79
this .ccToolchainProvider = toolchain ;
78
80
this .toolchainLibrariesSolibDir = toolchainLibrariesSolibDir ;
79
- this .outputArtifact = output ;
80
81
this .solibDir = solibDir ;
81
82
this .isLtoIndexing = isLtoIndexing ;
82
83
this .allLtoArtifacts = allLtoArtifacts ;
@@ -106,22 +107,81 @@ public LibrariesToLinkCollector(
106
107
// and the second could use $ORIGIN/../_solib_[arch]. But since this is a shared
107
108
// artifact, both are symlinks to the same place, so
108
109
// there's no *one* RPATH setting that fits all targets involved in the sharing.
109
- rpathRoot = ccToolchainProvider .getSolibDirectory () + "/" ;
110
+ potentialExecRoots = ImmutableList .of ();
111
+ rpathRoots = ImmutableList .of (ccToolchainProvider .getSolibDirectory () + "/" );
110
112
} else {
111
- // When executed from within a runfiles directory, the binary lies under a path such as
112
- // target.runfiles/some_repo/pkg/file, whereas the solib directory is located under
113
- // target.runfiles/main_repo.
114
- PathFragment runfilesPath = outputArtifact .getRunfilesPath ();
115
- String runfilesExecRoot ;
116
- if (runfilesPath .startsWith (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX )) {
117
- // runfilesPath is of the form ../some_repo/pkg/file, walk back some_repo/pkg and then
118
- // descend into the main workspace.
119
- runfilesExecRoot = "../" .repeat (runfilesPath .segmentCount () - 2 ) + workspaceName + "/" ;
120
- } else {
121
- // runfilesPath is of the form pkg/file, walk back pkg to reach the main workspace.
122
- runfilesExecRoot = "../" .repeat (runfilesPath .segmentCount () - 1 );
113
+ // The runtime location of the solib directory relative to the binary depends on four factors:
114
+ //
115
+ // * whether the binary is contained in the main repository or an external repository;
116
+ // * whether the binary is executed directly or from a runfiles tree;
117
+ // * whether the binary is staged as a symlink (sandboxed execution; local execution if the
118
+ // binary is in the runfiles of another target) or a regular file (remote execution) - the
119
+ // dynamic linker follows sandbox and runfiles symlinks into its location under the
120
+ // unsandboxed execroot, which thus becomes the effective $ORIGIN;
121
+ // * whether --experimental_sibling_repository_layout is enabled or not.
122
+ //
123
+ // The rpaths emitted into the binary thus have to cover the following cases (assuming that
124
+ // the binary target is located in the pkg `pkg` and has name `file`) for the directory used
125
+ // as $ORIGIN by the dynamic linker and the directory containing the solib directories:
126
+ //
127
+ // 1. main, direct, symlink:
128
+ // $ORIGIN: $EXECROOT/pkg
129
+ // solib root: $EXECROOT
130
+ // 2. main, direct, regular file:
131
+ // $ORIGIN: $EXECROOT/pkg
132
+ // solib root: $EXECROOT/pkg/file.runfiles/main_repo
133
+ // 3. main, runfiles, symlink:
134
+ // $ORIGIN: $EXECROOT/pkg
135
+ // solib root: $EXECROOT
136
+ // 4. main, runfiles, regular file:
137
+ // $ORIGIN: other_target.runfiles/main_repo/pkg
138
+ // solib root: other_target.runfiles/main_repo
139
+ // 5a. external, direct, symlink:
140
+ // $ORIGIN: $EXECROOT/external/other_repo/pkg
141
+ // solib root: $EXECROOT
142
+ // 5b. external, direct, symlink, with --experimental_sibling_repository_layout:
143
+ // $ORIGIN: $EXECROOT/../other_repo/pkg
144
+ // solib root: $EXECROOT/../other_repo
145
+ // 6a. external, direct, regular file:
146
+ // $ORIGIN: $EXECROOT/external/other_repo/pkg
147
+ // solib root: $EXECROOT/external/other_repo/pkg/file.runfiles/main_repo
148
+ // 6b. external, direct, regular file, with --experimental_sibling_repository_layout:
149
+ // $ORIGIN: $EXECROOT/../other_repo/pkg
150
+ // solib root: $EXECROOT/../other_repo/pkg/file.runfiles/other_repo
151
+ // 7a. external, runfiles, symlink:
152
+ // $ORIGIN: $EXECROOT/external/other_repo/pkg
153
+ // solib root: $EXECROOT
154
+ // 7b. external, runfiles, symlink, with --experimental_sibling_repository_layout:
155
+ // $ORIGIN: $EXECROOT/../other_repo/pkg
156
+ // solib root: $EXECROOT/../other_repo
157
+ // 8a. external, runfiles, regular file:
158
+ // $ORIGIN: other_target.runfiles/some_repo/pkg
159
+ // solib root: other_target.runfiles/main_repo
160
+ // 8b. external, runfiles, regular file, with --experimental_sibling_repository_layout:
161
+ // $ORIGIN: other_target.runfiles/some_repo/pkg
162
+ // solib root: other_target.runfiles/some_repo
163
+ //
164
+ // Cases 1, 3, 4, 5, 7, and 8b are covered by an rpath that walks up the root relative path.
165
+ // Case 8a is covered by walking up some_repo/pkg and then into main_repo.
166
+ // Cases 2 and 6 are currently not covered as they would require an rpath containing the
167
+ // binary filename, which may contain commas that would clash with the `-Wl` argument used to
168
+ // pass the rpath to the linker.
169
+ // TODO(#14600): Fix this by using `-Xlinker` instead of `-Wl`.
170
+ ImmutableList .Builder <String > execRoots = ImmutableList .builder ();
171
+ // Handles cases 1, 3, 4, 5, and 7.
172
+ execRoots .add ("../" .repeat (output .getRootRelativePath ().segmentCount () - 1 ));
173
+ if (output .getRunfilesPath ().startsWith (LabelConstants .EXTERNAL_RUNFILES_PATH_PREFIX )
174
+ && output .getRoot ().isLegacy ()) {
175
+ // Handles case 8a. The runfiles path is of the form ../some_repo/pkg/file and we need to
176
+ // walk up some_repo/pkg and then down into main_repo.
177
+ execRoots .add (
178
+ "../" .repeat (output .getRunfilesPath ().segmentCount () - 2 ) + workspaceName + "/" );
123
179
}
124
- rpathRoot = runfilesExecRoot + ccToolchainProvider .getSolibDirectory () + "/" ;
180
+
181
+ potentialExecRoots = execRoots .build ();
182
+ rpathRoots = potentialExecRoots .stream ()
183
+ .map ((execRoot ) -> execRoot + ccToolchainProvider .getSolibDirectory () + "/" )
184
+ .collect (toImmutableList ());
125
185
}
126
186
127
187
ltoMap = generateLtoMap ();
@@ -196,10 +256,10 @@ public CollectedLibrariesToLink collectLibrariesToLink() {
196
256
// directory. In other words, given blaze-bin/my/package/binary, rpathRoot would be
197
257
// "../../_solib_[arch]".
198
258
if (needToolchainLibrariesRpath ) {
199
- runtimeLibrarySearchDirectories . add (
200
- "../" . repeat ( outputArtifact . getRootRelativePath (). segmentCount () - 1 )
201
- + toolchainLibrariesSolibName
202
- + "/" );
259
+ for ( String potentialExecRoot : potentialExecRoots ) {
260
+ runtimeLibrarySearchDirectories . add (
261
+ potentialExecRoot + toolchainLibrariesSolibName + "/" );
262
+ }
203
263
}
204
264
if (isNativeDeps ) {
205
265
// We also retain the $ORIGIN/ path to solibs that are in _solib_<arch>, as opposed to
@@ -231,7 +291,9 @@ public CollectedLibrariesToLink collectLibrariesToLink() {
231
291
NestedSetBuilder <String > allRuntimeLibrarySearchDirectories = NestedSetBuilder .linkOrder ();
232
292
// rpath ordering matters for performance; first add the one where most libraries are found.
233
293
if (includeSolibDir ) {
234
- allRuntimeLibrarySearchDirectories .add (rpathRoot );
294
+ for (String rpathRoot : rpathRoots ) {
295
+ allRuntimeLibrarySearchDirectories .add (rpathRoot );
296
+ }
235
297
}
236
298
allRuntimeLibrarySearchDirectories .addAll (rpathRootsForExplicitSoDeps .build ());
237
299
if (includeToolchainLibrariesSolibDir ) {
@@ -346,17 +408,21 @@ private void addDynamicInputLinkOptions(
346
408
// When all dynamic deps are built in transitioned configurations, the default solib dir is
347
409
// not created. While resolving paths, the dynamic linker stops at the first directory that
348
410
// does not exist, even when followed by "../". We thus have to normalize the relative path.
349
- String relativePathToRoot =
350
- rpathRoot + dotdots + libDir .relativeTo (commonParent ).getPathString ();
351
- String normalizedPathToRoot = PathFragment .create (relativePathToRoot ).getPathString ();
352
- rpathRootsForExplicitSoDeps .add (normalizedPathToRoot );
411
+ for (String rpathRoot : rpathRoots ) {
412
+ String relativePathToRoot =
413
+ rpathRoot + dotdots + libDir .relativeTo (commonParent ).getPathString ();
414
+ String normalizedPathToRoot = PathFragment .create (relativePathToRoot ).getPathString ();
415
+ rpathRootsForExplicitSoDeps .add (normalizedPathToRoot );
416
+ }
353
417
354
418
// Unless running locally, libraries will be available under the root relative path, so we
355
419
// should add that to the rpath as well.
356
420
if (inputArtifact .getRootRelativePathString ().startsWith ("_solib_" )) {
357
421
PathFragment artifactPathUnderSolib = inputArtifact .getRootRelativePath ().subFragment (1 );
358
- rpathRootsForExplicitSoDeps .add (
359
- rpathRoot + artifactPathUnderSolib .getParentDirectory ().getPathString ());
422
+ for (String rpathRoot : rpathRoots ) {
423
+ rpathRootsForExplicitSoDeps .add (
424
+ rpathRoot + artifactPathUnderSolib .getParentDirectory ().getPathString ());
425
+ }
360
426
}
361
427
}
362
428
0 commit comments