Search in sources :

Example 1 with MutableDirectedGraph

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);
}
Also used : LinkedHashSet(java.util.LinkedHashSet) NativeLinkable(com.facebook.buck.cxx.NativeLinkable) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph)

Example 2 with MutableDirectedGraph

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);
    }
}
Also used : JavaDepsFinder(com.facebook.buck.jvm.java.autodeps.JavaDepsFinder) SortedSet(java.util.SortedSet) TreeSet(java.util.TreeSet) Set(java.util.Set) HashMap(java.util.HashMap) JavaFileParser(com.facebook.buck.jvm.java.JavaFileParser) SourcePath(com.facebook.buck.rules.SourcePath) PathSourcePath(com.facebook.buck.rules.PathSourcePath) TreeSet(java.util.TreeSet) JavaLibraryDescription(com.facebook.buck.jvm.java.JavaLibraryDescription) PathSourcePath(com.facebook.buck.rules.PathSourcePath) TreeMap(java.util.TreeMap) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph)

Example 3 with MutableDirectedGraph

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();
}
Also used : ImmutableMap(com.google.common.collect.ImmutableMap) ImmutableSet(com.google.common.collect.ImmutableSet) BuildTarget(com.facebook.buck.model.BuildTarget) AbstractBreadthFirstTraversal(com.facebook.buck.graph.AbstractBreadthFirstTraversal) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph)

Example 4 with MutableDirectedGraph

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());
}
Also used : TargetNode(com.facebook.buck.rules.TargetNode) HashMap(java.util.HashMap) BuildTarget(com.facebook.buck.model.BuildTarget) TargetGraph(com.facebook.buck.rules.TargetGraph) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph)

Example 5 with MutableDirectedGraph

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)));
    }
}
Also used : BroadcastEventListener(com.facebook.buck.event.listener.BroadcastEventListener) PerfEventId(com.facebook.buck.event.PerfEventId) BuckEvent(com.facebook.buck.event.BuckEvent) MoreMaps(com.facebook.buck.util.MoreMaps) TypeCoercerFactory(com.facebook.buck.rules.coercer.TypeCoercerFactory) Map(java.util.Map) AcyclicDepthFirstPostOrderTraversal(com.facebook.buck.graph.AcyclicDepthFirstPostOrderTraversal) Cell(com.facebook.buck.rules.Cell) Path(java.nio.file.Path) LinkedHashMultimap(com.google.common.collect.LinkedHashMultimap) Function(com.google.common.base.Function) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) TargetGraph(com.facebook.buck.rules.TargetGraph) Collection(java.util.Collection) BuildTargetException(com.facebook.buck.model.BuildTargetException) WatchEvents(com.facebook.buck.io.WatchEvents) BuildTarget(com.facebook.buck.model.BuildTarget) HasDefaultFlavors(com.facebook.buck.model.HasDefaultFlavors) ConstructorArgMarshaller(com.facebook.buck.rules.ConstructorArgMarshaller) Optional(java.util.Optional) SortedMap(java.util.SortedMap) ImplicitFlavorsInferringDescription(com.facebook.buck.rules.ImplicitFlavorsInferringDescription) ListeningExecutorService(com.google.common.util.concurrent.ListeningExecutorService) BuckEventBus(com.facebook.buck.event.BuckEventBus) Iterables(com.google.common.collect.Iterables) TargetGraphAndBuildTargets(com.facebook.buck.rules.TargetGraphAndBuildTargets) ListenableFuture(com.google.common.util.concurrent.ListenableFuture) SimplePerfEvent(com.facebook.buck.event.SimplePerfEvent) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph) HashMap(java.util.HashMap) Multimap(com.google.common.collect.Multimap) GraphTraversable(com.facebook.buck.graph.GraphTraversable) Iterators(com.google.common.collect.Iterators) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) TargetGroup(com.facebook.buck.rules.TargetGroup) Subscribe(com.google.common.eventbus.Subscribe) BuildFileParseException(com.facebook.buck.json.BuildFileParseException) Nullable(javax.annotation.Nullable) MoreCollectors(com.facebook.buck.util.MoreCollectors) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet) Logger(com.facebook.buck.log.Logger) Counter(com.facebook.buck.counters.Counter) TargetNode(com.facebook.buck.rules.TargetNode) WatchEvent(java.nio.file.WatchEvent) Throwables(com.google.common.base.Throwables) IOException(java.io.IOException) HumanReadableException(com.facebook.buck.util.HumanReadableException) Maps(com.google.common.collect.Maps) ExecutionException(java.util.concurrent.ExecutionException) Futures(com.google.common.util.concurrent.Futures) AbstractMap(java.util.AbstractMap) TreeMap(java.util.TreeMap) Preconditions(com.google.common.base.Preconditions) Flavor(com.facebook.buck.model.Flavor) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Collections(java.util.Collections) TargetNode(com.facebook.buck.rules.TargetNode) HashMap(java.util.HashMap) TargetGraph(com.facebook.buck.rules.TargetGraph) BuildTarget(com.facebook.buck.model.BuildTarget) HumanReadableException(com.facebook.buck.util.HumanReadableException) TargetGroup(com.facebook.buck.rules.TargetGroup) AcyclicDepthFirstPostOrderTraversal(com.facebook.buck.graph.AcyclicDepthFirstPostOrderTraversal) MutableDirectedGraph(com.facebook.buck.graph.MutableDirectedGraph)

Aggregations

MutableDirectedGraph (com.facebook.buck.graph.MutableDirectedGraph)7 BuildTarget (com.facebook.buck.model.BuildTarget)5 ImmutableSet (com.google.common.collect.ImmutableSet)4 TargetGraph (com.facebook.buck.rules.TargetGraph)3 TargetNode (com.facebook.buck.rules.TargetNode)3 ImmutableMap (com.google.common.collect.ImmutableMap)3 HashMap (java.util.HashMap)3 AbstractBreadthFirstTraversal (com.facebook.buck.graph.AbstractBreadthFirstTraversal)2 Cell (com.facebook.buck.rules.Cell)2 Path (java.nio.file.Path)2 Counter (com.facebook.buck.counters.Counter)1 NativeLinkable (com.facebook.buck.cxx.NativeLinkable)1 BuildJobStateBuildTarget (com.facebook.buck.distributed.thrift.BuildJobStateBuildTarget)1 BuildJobStateTargetGraph (com.facebook.buck.distributed.thrift.BuildJobStateTargetGraph)1 BuildJobStateTargetNode (com.facebook.buck.distributed.thrift.BuildJobStateTargetNode)1 BuckEvent (com.facebook.buck.event.BuckEvent)1 BuckEventBus (com.facebook.buck.event.BuckEventBus)1 PerfEventId (com.facebook.buck.event.PerfEventId)1 SimplePerfEvent (com.facebook.buck.event.SimplePerfEvent)1 BroadcastEventListener (com.facebook.buck.event.listener.BroadcastEventListener)1