use of com.facebook.buck.graph.MutableDirectedGraph in project buck by facebook.
the class NativeLibraryMergeEnhancer method getOrderedMergedConstituents.
/**
* Topo-sort the constituents objects so we can process deps first.
*/
private static Iterable<MergedNativeLibraryConstituents> getOrderedMergedConstituents(BuildRuleParams buildRuleParams, final Map<NativeLinkable, MergedNativeLibraryConstituents> linkableMembership) {
MutableDirectedGraph<MergedNativeLibraryConstituents> graph = new MutableDirectedGraph<>();
for (MergedNativeLibraryConstituents constituents : linkableMembership.values()) {
graph.addNode(constituents);
for (NativeLinkable constituentLinkable : constituents.getLinkables()) {
// For each dep of each constituent of each merged lib...
for (NativeLinkable dep : Iterables.concat(constituentLinkable.getNativeLinkableDeps(), constituentLinkable.getNativeLinkableExportedDeps())) {
// If that dep is in a different merged lib, add a dependency.
MergedNativeLibraryConstituents mergedDep = Preconditions.checkNotNull(linkableMembership.get(dep));
if (mergedDep != constituents) {
graph.addEdge(constituents, mergedDep);
}
}
}
}
// that actually shows the dependency cycle.
for (ImmutableSet<MergedNativeLibraryConstituents> fullCycle : graph.findCycles()) {
HashSet<MergedNativeLibraryConstituents> partialCycle = new LinkedHashSet<>();
MergedNativeLibraryConstituents item = fullCycle.iterator().next();
while (true) {
if (partialCycle.contains(item)) {
break;
}
partialCycle.add(item);
item = Sets.intersection(ImmutableSet.copyOf(graph.getOutgoingNodesFor(item)), fullCycle).iterator().next();
}
StringBuilder cycleString = new StringBuilder().append("[ ");
boolean foundStart = false;
for (MergedNativeLibraryConstituents member : partialCycle) {
if (member == item) {
foundStart = true;
}
if (foundStart) {
cycleString.append(member);
cycleString.append(" -> ");
}
}
cycleString.append(item);
cycleString.append(" ]");
throw new RuntimeException("Dependency cycle detected when merging native libs for " + buildRuleParams.getBuildTarget() + ": " + cycleString);
}
return TopologicalSort.sort(graph);
}
use of com.facebook.buck.graph.MutableDirectedGraph in project buck by facebook.
the class FineGrainedJavaDependencySuggester method suggestRefactoring.
/**
* Suggests a refactoring by printing it to stdout (with warnings printed to stderr).
* @throws IllegalArgumentException
*/
void suggestRefactoring() {
final TargetNode<?, ?> suggestedNode = graph.get(suggestedTarget);
if (!(suggestedNode.getConstructorArg() instanceof JavaLibraryDescription.Arg)) {
console.printErrorText(String.format("'%s' does not correspond to a Java rule", suggestedTarget));
throw new IllegalArgumentException();
}
JavaLibraryDescription.Arg arg = (JavaLibraryDescription.Arg) suggestedNode.getConstructorArg();
JavaFileParser javaFileParser = javaDepsFinder.getJavaFileParser();
Multimap<String, String> providedSymbolToRequiredSymbols = HashMultimap.create();
Map<String, PathSourcePath> providedSymbolToSrc = new HashMap<>();
for (SourcePath src : arg.srcs) {
extractProvidedSymbolInfoFromSourceFile(src, javaFileParser, providedSymbolToRequiredSymbols, providedSymbolToSrc);
}
// Create a MutableDirectedGraph from the providedSymbolToRequiredSymbols.
MutableDirectedGraph<String> symbolsDependencies = new MutableDirectedGraph<>();
// dependencies.
for (String providedSymbol : providedSymbolToSrc.keySet()) {
// Add a node for the providedSymbol in case it has no edges.
symbolsDependencies.addNode(providedSymbol);
for (String requiredSymbol : providedSymbolToRequiredSymbols.get(providedSymbol)) {
if (providedSymbolToRequiredSymbols.containsKey(requiredSymbol) && !providedSymbol.equals(requiredSymbol)) {
symbolsDependencies.addEdge(providedSymbol, requiredSymbol);
}
}
}
// Determine the strongly connected components.
Set<Set<String>> stronglyConnectedComponents = symbolsDependencies.findStronglyConnectedComponents();
// Maps a providedSymbol to the component that contains it.
Map<String, NamedStronglyConnectedComponent> namedComponentsIndex = new TreeMap<>();
Set<NamedStronglyConnectedComponent> namedComponents = new TreeSet<>();
for (Set<String> stronglyConnectedComponent : stronglyConnectedComponents) {
// We just use the first provided symbol in the strongly connected component as the canonical
// name for the component. Maybe not the best name, but certainly not the worst.
String name = Iterables.getFirst(stronglyConnectedComponent, /* defaultValue */
null);
if (name == null) {
throw new IllegalStateException("A strongly connected component was created with zero nodes.");
}
NamedStronglyConnectedComponent namedComponent = new NamedStronglyConnectedComponent(name, stronglyConnectedComponent);
namedComponents.add(namedComponent);
for (String providedSymbol : stronglyConnectedComponent) {
namedComponentsIndex.put(providedSymbol, namedComponent);
}
}
// Visibility argument.
StringBuilder visibilityBuilder = new StringBuilder(" visibility = [\n");
SortedSet<String> visibilities = FluentIterable.from(suggestedNode.getVisibilityPatterns()).transform(VisibilityPattern::getRepresentation).toSortedSet(Ordering.natural());
for (String visibility : visibilities) {
visibilityBuilder.append(" '" + visibility + "',\n");
}
visibilityBuilder.append(" ],\n");
String visibilityArg = visibilityBuilder.toString();
// Print out the new version of the original rule.
console.getStdOut().printf("java_library(\n" + " name = '%s',\n" + " exported_deps = [\n", suggestedTarget.getShortName());
for (NamedStronglyConnectedComponent namedComponent : namedComponents) {
console.getStdOut().printf(" ':%s',\n", namedComponent.name);
}
console.getStdOut().print(" ],\n" + visibilityArg + ")\n");
// Print out a rule for each of the strongly connected components.
JavaDepsFinder.DependencyInfo dependencyInfo = javaDepsFinder.findDependencyInfoForGraph(graph);
for (NamedStronglyConnectedComponent namedComponent : namedComponents) {
String buildRuleDefinition = createBuildRuleDefinition(namedComponent, providedSymbolToSrc, providedSymbolToRequiredSymbols, namedComponentsIndex, dependencyInfo, symbolsDependencies, visibilityArg);
console.getStdOut().print(buildRuleDefinition);
}
}
use of com.facebook.buck.graph.MutableDirectedGraph in project buck by facebook.
the class NativeLinkables method getNativeLinkables.
/**
* Extract from the dependency graph all the libraries which must be considered for linking.
*
* Traversal proceeds depending on whether each dependency is to be statically or dynamically
* linked.
*
* @param linkStyle how dependencies should be linked, if their preferred_linkage is
* {@code NativeLinkable.Linkage.ANY}.
*/
public static ImmutableMap<BuildTarget, NativeLinkable> getNativeLinkables(final CxxPlatform cxxPlatform, Iterable<? extends NativeLinkable> inputs, final Linker.LinkableDepType linkStyle, final Predicate<? super NativeLinkable> traverse) {
final Map<BuildTarget, NativeLinkable> nativeLinkables = Maps.newHashMap();
for (NativeLinkable nativeLinkable : inputs) {
nativeLinkables.put(nativeLinkable.getBuildTarget(), nativeLinkable);
}
final MutableDirectedGraph<BuildTarget> graph = new MutableDirectedGraph<>();
AbstractBreadthFirstTraversal<BuildTarget> visitor = new AbstractBreadthFirstTraversal<BuildTarget>(nativeLinkables.keySet()) {
@Override
public ImmutableSet<BuildTarget> visit(BuildTarget target) {
NativeLinkable nativeLinkable = Preconditions.checkNotNull(nativeLinkables.get(target));
graph.addNode(target);
// We always traverse a rule's exported native linkables.
Iterable<? extends NativeLinkable> nativeLinkableDeps = nativeLinkable.getNativeLinkableExportedDepsForPlatform(cxxPlatform);
boolean shouldTraverse = true;
switch(nativeLinkable.getPreferredLinkage(cxxPlatform)) {
case ANY:
shouldTraverse = linkStyle != Linker.LinkableDepType.SHARED;
break;
case SHARED:
shouldTraverse = false;
break;
case STATIC:
shouldTraverse = true;
break;
}
// If we're linking this dependency statically, we also need to traverse its deps.
if (shouldTraverse) {
nativeLinkableDeps = Iterables.concat(nativeLinkableDeps, nativeLinkable.getNativeLinkableDepsForPlatform(cxxPlatform));
}
// Process all the traversable deps.
ImmutableSet.Builder<BuildTarget> deps = ImmutableSet.builder();
for (NativeLinkable dep : nativeLinkableDeps) {
if (traverse.apply(dep)) {
BuildTarget depTarget = dep.getBuildTarget();
graph.addEdge(target, depTarget);
deps.add(depTarget);
nativeLinkables.put(depTarget, dep);
}
}
return deps.build();
}
};
visitor.start();
// Topologically sort the rules.
Iterable<BuildTarget> ordered = TopologicalSort.sort(graph).reverse();
// Return a map of of the results.
ImmutableMap.Builder<BuildTarget, NativeLinkable> result = ImmutableMap.builder();
for (BuildTarget target : ordered) {
result.put(target, nativeLinkables.get(target));
}
return result.build();
}
use of com.facebook.buck.graph.MutableDirectedGraph in project buck by facebook.
the class TargetGraphFactory method newInstance.
public static TargetGraph newInstance(Iterable<TargetNode<?, ?>> nodes) {
Map<BuildTarget, TargetNode<?, ?>> builder = new HashMap<>();
for (TargetNode<?, ?> node : nodes) {
builder.put(node.getBuildTarget(), node);
BuildTarget unflavoredTarget = BuildTarget.of(node.getBuildTarget().getUnflavoredBuildTarget());
if (node.getBuildTarget().isFlavored() && !builder.containsKey(unflavoredTarget)) {
builder.put(unflavoredTarget, node);
}
}
ImmutableMap<BuildTarget, TargetNode<?, ?>> map = ImmutableMap.copyOf(builder);
MutableDirectedGraph<TargetNode<?, ?>> graph = new MutableDirectedGraph<>();
for (TargetNode<?, ?> node : map.values()) {
graph.addNode(node);
for (BuildTarget dep : node.getDeps()) {
graph.addEdge(node, Preconditions.checkNotNull(map.get(dep), dep));
}
}
return new TargetGraph(graph, map, ImmutableSet.of());
}
use of com.facebook.buck.graph.MutableDirectedGraph in project buck by facebook.
the class Parser method buildTargetGraph.
@SuppressWarnings("PMD.PrematureDeclaration")
protected TargetGraph buildTargetGraph(final PerBuildState state, final BuckEventBus eventBus, final Iterable<BuildTarget> toExplore, final boolean ignoreBuckAutodepsFiles) throws IOException, InterruptedException, BuildFileParseException, BuildTargetException {
if (Iterables.isEmpty(toExplore)) {
return TargetGraph.EMPTY;
}
final Map<BuildTarget, TargetGroup> groups = Maps.newHashMap();
for (TargetGroup group : state.getAllGroups()) {
groups.put(group.getBuildTarget(), group);
}
final MutableDirectedGraph<TargetNode<?, ?>> graph = new MutableDirectedGraph<>();
final Map<BuildTarget, TargetNode<?, ?>> index = new HashMap<>();
ParseEvent.Started parseStart = ParseEvent.started(toExplore);
eventBus.post(parseStart);
GraphTraversable<BuildTarget> traversable = target -> {
TargetNode<?, ?> node;
try {
node = state.getTargetNode(target);
} catch (BuildFileParseException | BuildTargetException e) {
throw new RuntimeException(e);
}
if (ignoreBuckAutodepsFiles) {
return Collections.emptyIterator();
}
for (BuildTarget dep : node.getDeps()) {
try {
state.getTargetNode(dep);
} catch (BuildFileParseException | BuildTargetException | HumanReadableException e) {
throw new HumanReadableException(e, "Couldn't get dependency '%s' of target '%s':\n%s", dep, target, e.getMessage());
}
}
return node.getDeps().iterator();
};
GraphTraversable<BuildTarget> groupExpander = target -> {
TargetGroup group = Preconditions.checkNotNull(groups.get(target), "SANITY FAILURE: Tried to expand group %s but it doesn't exist.", target);
return Iterators.filter(group.iterator(), groups::containsKey);
};
AcyclicDepthFirstPostOrderTraversal<BuildTarget> targetGroupExpansion = new AcyclicDepthFirstPostOrderTraversal<>(groupExpander);
AcyclicDepthFirstPostOrderTraversal<BuildTarget> targetNodeTraversal = new AcyclicDepthFirstPostOrderTraversal<>(traversable);
TargetGraph targetGraph = null;
try {
for (BuildTarget target : targetNodeTraversal.traverse(toExplore)) {
TargetNode<?, ?> targetNode = state.getTargetNode(target);
Preconditions.checkNotNull(targetNode, "No target node found for %s", target);
graph.addNode(targetNode);
MoreMaps.putCheckEquals(index, target, targetNode);
if (target.isFlavored()) {
BuildTarget unflavoredTarget = BuildTarget.of(target.getUnflavoredBuildTarget());
MoreMaps.putCheckEquals(index, unflavoredTarget, state.getTargetNode(unflavoredTarget));
}
for (BuildTarget dep : targetNode.getDeps()) {
graph.addEdge(targetNode, state.getTargetNode(dep));
}
}
for (BuildTarget groupTarget : targetGroupExpansion.traverse(groups.keySet())) {
ImmutableMap<BuildTarget, Iterable<BuildTarget>> replacements = Maps.toMap(groupExpander.findChildren(groupTarget), target -> {
TargetGroup group = groups.get(target);
return Preconditions.checkNotNull(group, "SANITY FAILURE: Tried to expand group %s but it doesn't exist.", target);
});
if (!replacements.isEmpty()) {
// TODO(tophyr): Stop duplicating target lists
groups.put(groupTarget, Preconditions.checkNotNull(groups.get(groupTarget)).withReplacedTargets(replacements));
}
}
targetGraph = new TargetGraph(graph, ImmutableMap.copyOf(index), ImmutableSet.copyOf(groups.values()));
state.ensureConcreteFilesExist(eventBus);
return targetGraph;
} catch (AcyclicDepthFirstPostOrderTraversal.CycleException e) {
throw new HumanReadableException(e.getMessage());
} catch (RuntimeException e) {
throw propagateRuntimeCause(e);
} finally {
eventBus.post(ParseEvent.finished(parseStart, Optional.ofNullable(targetGraph)));
}
}
Aggregations