Skip to content

Commit

Permalink
C++: First step in removing CcLinkParams
Browse files Browse the repository at this point in the history
Introduces intermediate class that encapsulates all the information needed. Only CcLibrary is migrated in this CL.

RELNOTES:none
PiperOrigin-RevId: 220059263
  • Loading branch information
oquenchil authored and Copybara-Service committed Nov 5, 2018
1 parent 7bf7f03 commit 1db9e66
Show file tree
Hide file tree
Showing 3 changed files with 788 additions and 18 deletions.
264 changes: 247 additions & 17 deletions src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static java.util.stream.Collectors.joining;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
Expand Down Expand Up @@ -52,12 +53,15 @@
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
import com.google.devtools.build.lib.rules.cpp.Link.LinkTargetType;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.SolibLibraryToLink;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileTypeSet;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* A ConfiguredTarget for <code>cc_library</code> rules.
Expand Down Expand Up @@ -353,13 +357,24 @@ public static void init(
ccLinkingOutputs,
precompiledStaticLibraries,
precompiledPicStaticLibraries,
/* dynamicLibrariesForLinking= */ dynamicLibraries,
/* dynamicLibrariesForRuntime= */ dynamicLibraries,
dynamicLibraries,
ccCompilationOutputs);

ImmutableList<LibraryToLinkWrapper> libraryToLinkWrappers = ImmutableList.of();
if (!neverLink) {
libraryToLinkWrappers =
createLibraryToLinkWrappersList(
ruleContext,
ccLinkingOutputs,
precompiledStaticLibraries,
precompiledPicStaticLibraries,
dynamicLibraries,
ccCompilationOutputs);
}

CcLinkingInfo ccLinkingInfo =
linkingHelper.buildCcLinkingInfo(
ccLinkingOutputsWithPrecompiledLibraries, compilationInfo.getCcCompilationContext());
linkingHelper.buildCcLinkingInfoFromLibraryToLinkWrappers(
libraryToLinkWrappers, compilationInfo.getCcCompilationContext());
CcNativeLibraryProvider ccNativeLibraryProvider =
CppHelper.collectNativeCcLibraries(
ruleContext.getPrerequisites("deps", Mode.TARGET),
Expand Down Expand Up @@ -602,32 +617,255 @@ private static Map<String, NestedSet<Artifact>> addLinkerOutputArtifacts(
return outputGroups.build();
}

private static ImmutableList<LibraryToLinkWrapper> createLibraryToLinkWrappersList(
RuleContext ruleContext,
CcLinkingOutputs ccLinkingOutputs,
List<LibraryToLink> staticLibraries,
List<LibraryToLink> picStaticLibraries,
List<LibraryToLink> dynamicLibrariesForRuntime,
CcCompilationOutputs ccCompilationOutputs) {
Preconditions.checkState(ccLinkingOutputs.getStaticLibraries().size() <= 1);
Preconditions.checkState(ccLinkingOutputs.getPicStaticLibraries().size() <= 1);
Preconditions.checkState(ccLinkingOutputs.getDynamicLibrariesForLinking().size() <= 1);
Preconditions.checkState(ccLinkingOutputs.getDynamicLibrariesForRuntime().size() <= 1);

ImmutableList.Builder<LibraryToLinkWrapper> libraryToLinkWrappers = ImmutableList.builder();

checkIfLinkOutputsCollidingWithPrecompiledFiles(
ruleContext,
ccLinkingOutputs,
staticLibraries,
picStaticLibraries,
dynamicLibrariesForRuntime,
ccCompilationOutputs);

if (ruleContext.hasErrors()) {
return libraryToLinkWrappers.build();
}

// For cc_library if it contains precompiled libraries we link them. If it contains normal
// sources we link them as well, if it doesn't contain normal sources, then we don't do
// anything else if there were precompiled libraries. However, if there are no precompiled
// libraries and there are no normal sources, then we use the implicitly created link output
// files if they exist.
libraryToLinkWrappers.addAll(
convertPrecompiledLibrariesToLibraryToLinkWrapper(
staticLibraries, picStaticLibraries, dynamicLibrariesForRuntime));
if (!ccCompilationOutputs.isEmpty()
|| (staticLibraries.isEmpty()
&& picStaticLibraries.isEmpty()
&& dynamicLibrariesForRuntime.isEmpty()
&& isContentsOfCcLinkingOutputsImplicitlyCreated(
ccCompilationOutputs, ccLinkingOutputs))) {
LibraryToLinkWrapper linkOutputsLibraryToLinkWrapper =
convertLinkOutputsToLibraryToLinkWrapper(ccLinkingOutputs);
if (linkOutputsLibraryToLinkWrapper != null) {
libraryToLinkWrappers.add(linkOutputsLibraryToLinkWrapper);
}
}

return libraryToLinkWrappers.build();
}

private static boolean isContentsOfCcLinkingOutputsImplicitlyCreated(
CcCompilationOutputs ccCompilationOutputs, CcLinkingOutputs ccLinkingOutputs) {
return ccCompilationOutputs.isEmpty() && !ccLinkingOutputs.isEmpty();
}

private static List<LibraryToLinkWrapper> convertPrecompiledLibrariesToLibraryToLinkWrapper(
List<LibraryToLink> staticLibraries,
List<LibraryToLink> picStaticLibraries,
List<LibraryToLink> dynamicLibrariesForRuntime) {
ImmutableList.Builder<LibraryToLinkWrapper> libraryToLinkWrappers = ImmutableList.builder();

Set<String> identifiersUsed = new HashSet<>();
// Here we hae an O(n^2) algorithm, the size of the inputs is never big though, we only work
// here with the local libraries, none of the libraries of the transitive closure.
for (LibraryToLink staticLibrary : staticLibraries) {
LibraryToLinkWrapper.Builder libraryToLinkWrapperBuilder = LibraryToLinkWrapper.builder();
libraryToLinkWrapperBuilder.setStaticLibrary(staticLibrary.getArtifact());
String identifier = staticLibrary.getLibraryIdentifier();
libraryToLinkWrapperBuilder.setLibraryIdentifier(identifier);
List<LibraryToLink> sameIdentifierPicStaticLibraries =
picStaticLibraries.stream()
.filter(x -> x.getLibraryIdentifier().equals(identifier))
.collect(ImmutableList.toImmutableList());
if (!sameIdentifierPicStaticLibraries.isEmpty()) {
libraryToLinkWrapperBuilder.setPicStaticLibrary(
sameIdentifierPicStaticLibraries.get(0).getArtifact());
}
List<LibraryToLink> sameIdentifierDynamicLibraries =
dynamicLibrariesForRuntime.stream()
.filter(x -> x.getLibraryIdentifier().equals(identifier))
.collect(ImmutableList.toImmutableList());
if (!sameIdentifierDynamicLibraries.isEmpty()) {
LibraryToLink dynamicLibrary = sameIdentifierDynamicLibraries.get(0);
libraryToLinkWrapperBuilder.setDynamicLibrary(dynamicLibrary.getArtifact());
if (dynamicLibrary instanceof SolibLibraryToLink) {
libraryToLinkWrapperBuilder.setResolvedSymlinkDynamicLibrary(
dynamicLibrary.getOriginalLibraryArtifact());
}
}
libraryToLinkWrapperBuilder.setAlwayslink(
staticLibrary.getArtifactCategory() == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY);
identifiersUsed.add(identifier);
libraryToLinkWrappers.add(libraryToLinkWrapperBuilder.build());
}

for (LibraryToLink picStaticLibrary : picStaticLibraries) {
String identifier = picStaticLibrary.getLibraryIdentifier();
if (identifiersUsed.contains(identifier)) {
continue;
}
LibraryToLinkWrapper.Builder libraryToLinkWrapperBuilder = LibraryToLinkWrapper.builder();
libraryToLinkWrapperBuilder.setPicStaticLibrary(picStaticLibrary.getArtifact());
libraryToLinkWrapperBuilder.setLibraryIdentifier(identifier);
List<LibraryToLink> sameIdentifierDynamicLibraries =
dynamicLibrariesForRuntime.stream()
.filter(x -> x.getLibraryIdentifier().equals(identifier))
.collect(ImmutableList.toImmutableList());
if (!sameIdentifierDynamicLibraries.isEmpty()) {
LibraryToLink dynamicLibrary = sameIdentifierDynamicLibraries.get(0);
libraryToLinkWrapperBuilder.setDynamicLibrary(dynamicLibrary.getArtifact());
if (dynamicLibrary instanceof SolibLibraryToLink) {
libraryToLinkWrapperBuilder.setResolvedSymlinkDynamicLibrary(
dynamicLibrary.getOriginalLibraryArtifact());
}
}
libraryToLinkWrapperBuilder.setAlwayslink(
picStaticLibrary.getArtifactCategory() == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY);
identifiersUsed.add(identifier);
libraryToLinkWrappers.add(libraryToLinkWrapperBuilder.build());
}

for (LibraryToLink dynamicLibrary : dynamicLibrariesForRuntime) {
String identifier = dynamicLibrary.getLibraryIdentifier();
if (identifiersUsed.contains(identifier)) {
continue;
}
LibraryToLinkWrapper.Builder libraryToLinkWrapperBuilder = LibraryToLinkWrapper.builder();
libraryToLinkWrapperBuilder.setDynamicLibrary(dynamicLibrary.getArtifact());
libraryToLinkWrapperBuilder.setLibraryIdentifier(identifier);
if (dynamicLibrary instanceof SolibLibraryToLink) {
libraryToLinkWrapperBuilder.setResolvedSymlinkDynamicLibrary(
dynamicLibrary.getOriginalLibraryArtifact());
}
libraryToLinkWrappers.add(libraryToLinkWrapperBuilder.build());
}
return libraryToLinkWrappers.build();
}

private static LibraryToLinkWrapper convertLinkOutputsToLibraryToLinkWrapper(
CcLinkingOutputs ccLinkingOutputs) {
Preconditions.checkState(!ccLinkingOutputs.isEmpty());

LibraryToLinkWrapper.Builder libraryToLinkWrapperBuilder = LibraryToLinkWrapper.builder();
if (!ccLinkingOutputs.getStaticLibraries().isEmpty()) {
LibraryToLink staticLibrary = ccLinkingOutputs.getStaticLibraries().get(0);
libraryToLinkWrapperBuilder.setStaticLibrary(staticLibrary.getArtifact());
libraryToLinkWrapperBuilder.setObjectFiles(
ImmutableList.copyOf(staticLibrary.getObjectFiles()));
libraryToLinkWrapperBuilder.setLtoBitcodeFiles(
ImmutableMap.copyOf(staticLibrary.getLtoBitcodeFiles()));
libraryToLinkWrapperBuilder.setSharedNonLtoBackends(
ImmutableMap.copyOf(staticLibrary.getSharedNonLtoBackends()));
libraryToLinkWrapperBuilder.setAlwayslink(
staticLibrary.getArtifactCategory() == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY);
libraryToLinkWrapperBuilder.setLibraryIdentifier(staticLibrary.getLibraryIdentifier());
}

if (!ccLinkingOutputs.getPicStaticLibraries().isEmpty()) {
LibraryToLink picStaticLibrary = ccLinkingOutputs.getPicStaticLibraries().get(0);
libraryToLinkWrapperBuilder.setPicStaticLibrary(picStaticLibrary.getArtifact());
libraryToLinkWrapperBuilder.setPicObjectFiles(
ImmutableList.copyOf(picStaticLibrary.getObjectFiles()));
libraryToLinkWrapperBuilder.setPicLtoBitcodeFiles(
ImmutableMap.copyOf(picStaticLibrary.getLtoBitcodeFiles()));
libraryToLinkWrapperBuilder.setPicSharedNonLtoBackends(
ImmutableMap.copyOf(picStaticLibrary.getSharedNonLtoBackends()));
libraryToLinkWrapperBuilder.setAlwayslink(
picStaticLibrary.getArtifactCategory() == ArtifactCategory.ALWAYSLINK_STATIC_LIBRARY);
libraryToLinkWrapperBuilder.setLibraryIdentifier(picStaticLibrary.getLibraryIdentifier());
}

if (!ccLinkingOutputs.getDynamicLibrariesForLinking().isEmpty()) {
LibraryToLink dynamicLibraryForLinking =
ccLinkingOutputs.getDynamicLibrariesForLinking().get(0);
Preconditions.checkState(!ccLinkingOutputs.getDynamicLibrariesForRuntime().isEmpty());
LibraryToLink dynamicLibraryForRuntime =
ccLinkingOutputs.getDynamicLibrariesForRuntime().get(0);
if (dynamicLibraryForLinking != dynamicLibraryForRuntime) {
libraryToLinkWrapperBuilder.setInterfaceLibrary(dynamicLibraryForLinking.getArtifact());
if (dynamicLibraryForLinking instanceof SolibLibraryToLink) {
libraryToLinkWrapperBuilder.setResolvedSymlinkInterfaceLibrary(
dynamicLibraryForLinking.getOriginalLibraryArtifact());
}
libraryToLinkWrapperBuilder.setDynamicLibrary(dynamicLibraryForRuntime.getArtifact());
if (dynamicLibraryForRuntime instanceof SolibLibraryToLink) {
libraryToLinkWrapperBuilder.setResolvedSymlinkDynamicLibrary(
dynamicLibraryForRuntime.getOriginalLibraryArtifact());
}
} else {
libraryToLinkWrapperBuilder.setDynamicLibrary(dynamicLibraryForRuntime.getArtifact());
if (dynamicLibraryForRuntime instanceof SolibLibraryToLink) {
libraryToLinkWrapperBuilder.setResolvedSymlinkDynamicLibrary(
dynamicLibraryForRuntime.getOriginalLibraryArtifact());
}
}
libraryToLinkWrapperBuilder.setLibraryIdentifier(
dynamicLibraryForLinking.getLibraryIdentifier());
}
return libraryToLinkWrapperBuilder.build();
}

private static CcLinkingOutputs addPrecompiledLibrariesToLinkingOutputs(
RuleContext ruleContext,
CcLinkingOutputs ccLinkingOutputs,
List<LibraryToLink> staticLibraries,
List<LibraryToLink> picStaticLibraries,
List<LibraryToLink> dynamicLibrariesForLinking,
List<LibraryToLink> dynamicLibrariesForRuntime,
CcCompilationOutputs ccCompilationOutputs) {
if (staticLibraries.isEmpty()
&& picStaticLibraries.isEmpty()
&& dynamicLibrariesForLinking.isEmpty()
&& dynamicLibrariesForRuntime.isEmpty()) {
return ccLinkingOutputs;
}

CcLinkingOutputs.Builder newOutputsBuilder = new CcLinkingOutputs.Builder();
if (!ccCompilationOutputs.isEmpty()) {
// Add the linked outputs of this rule iff we had anything to put in them, but then
// make sure we're not colliding with some library added from the inputs.
newOutputsBuilder.merge(ccLinkingOutputs);
}

checkIfLinkOutputsCollidingWithPrecompiledFiles(
ruleContext,
ccLinkingOutputs,
staticLibraries,
picStaticLibraries,
dynamicLibrariesForRuntime,
ccCompilationOutputs);

// Merge the pre-compiled libraries (static & dynamic) into the linker outputs.
return newOutputsBuilder
.addStaticLibraries(staticLibraries)
.addPicStaticLibraries(picStaticLibraries)
.addDynamicLibraries(dynamicLibrariesForRuntime)
.addDynamicLibrariesForRuntime(dynamicLibrariesForRuntime)
.build();
}

private static void checkIfLinkOutputsCollidingWithPrecompiledFiles(
RuleContext ruleContext,
CcLinkingOutputs ccLinkingOutputs,
List<LibraryToLink> staticLibraries,
List<LibraryToLink> picStaticLibraries,
List<LibraryToLink> dynamicLibrariesForRuntime,
CcCompilationOutputs ccCompilationOutputs) {
if (!ccCompilationOutputs.isEmpty()) {
ImmutableSetMultimap<String, LibraryToLink> precompiledLibraryMap =
CcLinkingOutputs.getLibrariesByIdentifier(
Iterables.concat(
staticLibraries,
picStaticLibraries,
dynamicLibrariesForLinking,
dynamicLibrariesForRuntime));
ImmutableSetMultimap<String, LibraryToLink> linkedLibraryMap =
ccLinkingOutputs.getLibrariesByIdentifier();
Expand All @@ -654,13 +892,5 @@ private static CcLinkingOutputs addPrecompiledLibrariesToLinkingOutputs(
+ "which could cause confusion");
}
}

// Merge the pre-compiled libraries (static & dynamic) into the linker outputs.
return newOutputsBuilder
.addStaticLibraries(staticLibraries)
.addPicStaticLibraries(picStaticLibraries)
.addDynamicLibraries(dynamicLibrariesForLinking)
.addDynamicLibrariesForRuntime(dynamicLibrariesForRuntime)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@


import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
Expand Down Expand Up @@ -367,6 +368,23 @@ public CcLinkingOutputs link(CcCompilationOutputs ccOutputs)
return ccLinkingOutputs;
}

public CcLinkingInfo buildCcLinkingInfoFromLibraryToLinkWrappers(
ImmutableCollection<LibraryToLinkWrapper> libraryToLinkWrappers,
CcCompilationContext ccCompilationContext) {
CcLinkingInfo ccLinkingInfo =
LibraryToLinkWrapper.toCcLinkingInfo(
cppConfiguration.forcePic(),
libraryToLinkWrappers,
ImmutableList.copyOf(linkopts),
linkstamps.build(),
ccCompilationContext,
nonCodeLinkerInputs);
ImmutableList.Builder<CcLinkingInfo> mergedCcLinkingInfos = ImmutableList.builder();
mergedCcLinkingInfos.add(ccLinkingInfo);
mergedCcLinkingInfos.addAll(ccLinkingInfos);
return CcLinkingInfo.merge(mergedCcLinkingInfos.build());
}

public CcLinkingInfo buildCcLinkingInfo(
CcLinkingOutputs ccLinkingOutputs, CcCompilationContext ccCompilationContext) {
Preconditions.checkNotNull(ccCompilationContext);
Expand Down Expand Up @@ -466,7 +484,12 @@ private CcLinkingOutputs createCcLinkActions(CcCompilationOutputs ccOutputs)
createDynamicLibrary(result, env, usePic, libraryIdentifier, ccOutputs);
}

return result.build();
CcLinkingOutputs ccLinkingOutputs = result.build();
Preconditions.checkState(ccLinkingOutputs.getStaticLibraries().size() <= 1);
Preconditions.checkState(ccLinkingOutputs.getPicStaticLibraries().size() <= 1);
Preconditions.checkState(ccLinkingOutputs.getDynamicLibrariesForLinking().size() <= 1);
Preconditions.checkState(ccLinkingOutputs.getDynamicLibrariesForRuntime().size() <= 1);
return ccLinkingOutputs;
}

public CcLinkingHelper setWillOnlyBeLinkedIntoDynamicLibraries(
Expand Down
Loading

0 comments on commit 1db9e66

Please sign in to comment.