summaryrefslogtreecommitdiffstats
path: root/tools/gn/item_tree.h
blob: 59de49f3a08e8c8884cc74cf145ceb7f3bfbdbec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef TOOLS_GN_ITEM_TREE_H_
#define TOOLS_GN_ITEM_TREE_H_

#include "base/containers/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "tools/gn/label.h"

class BuildSettings;
class Err;
class Item;
class ItemNode;

// Represents the full dependency tree if labeled items in the system.
// Generally you will interact with this through the target manager, etc.
//
// There are two modes for filling out the dependency tree:
//
// - In greedy mode, every target we encounter will be generated. This means
//   that we'll recursively load all of its subdependencies. So if you have
//   a build file that's loaded for any reason, all targets in that build file
//   will be generated.
//
// - In non-greedy mode, we'll only generate and load dependncies for targets
//   that have the should_generate bit set. This allows us to load the minimal
//   set of buildfiles required for one or more targets.
//
// The main build is generally run in greedy mode, since people expect to be
// be able to write random tests and have them show up in the output. We'll
// switch into non-greed mode when doing diagnostics (like displaying the
// dependency tree on the command line) and for dependencies on targets in
// other toolchains. The toolchain behavior is important, if target A depends
// on B with an alternate toolchain, it doesn't mean we should recursively
// generate all targets in the buildfile just to get B: we should generate the
// and load the minimum number of files in order to resolve B.
class ItemTree {
 public:
  ItemTree();
  ~ItemTree();

  // This lock must be held when calling the "Locked" functions below.
  base::Lock& lock() const { return lock_; }

  // Returns NULL if the item is not found.
  //
  // The lock must be held.
  ItemNode* GetExistingNodeLocked(const Label& label);

  // There must not be an item with this label in the tree already. Takes
  // ownership of the pointer.
  //
  // The lock must be held.
  void AddNodeLocked(ItemNode* node);

  // Mark the given item as being defined. If it has no unresolved
  // dependencies, it will be marked resolved, and the resolved state will be
  // recursively pushed into the dependency tree. Returns an error if there was
  // an error.
  bool MarkItemDefinedLocked(const BuildSettings* build_settings,
                             const Label& label,
                             Err* err);

  // Fills the given vector with all known items.
  void GetAllItemNodesLocked(std::vector<const ItemNode*>* dest) const;
  void GetAllItemsLocked(std::vector<const Item*>* dest) const;

  // Returns an error if there are unresolved dependencies, or no error if
  // there aren't.
  //
  // The lock should not be held.
  Err CheckForBadItems() const;

 private:
  void MarkItemResolvedLocked(ItemNode* node);

  // Given a set of unresolved nodes, looks for cycles and returns the error
  // message describing any cycles it found.
  std::string CheckForCircularDependenciesLocked(
      const std::vector<const ItemNode*>& bad_nodes) const;

  mutable base::Lock lock_;

  typedef base::hash_map<Label, ItemNode*> StringToNodeHash;
  StringToNodeHash items_;  // Owning pointer.

  DISALLOW_COPY_AND_ASSIGN(ItemTree);
};

#endif  // TOOLS_GN_ITEM_TREE_H_