file_dependencies.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //=======================================================================
  2. // Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
  3. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //=======================================================================
  9. // Some small modifications are done by Alexander Holler
  10. /*
  11. Paul Moore's request:
  12. As an example of a practical problem which is not restricted to graph
  13. "experts", consider file dependencies. It's basically graph construction,
  14. plus topological sort, but it might make a nice "tutorial" example. Build a
  15. dependency graph of files, then use the algorithms to do things like
  16. 1. Produce a full recompilation order (topological sort, by modified date)
  17. 2. Produce a "parallel" recompilation order (same as above, but group files
  18. which can be built in parallel)
  19. 3. Change analysis (if I change file x, which others need recompiling)
  20. 4. Dependency changes (if I add a dependency between file x and file y, what
  21. are the effects)
  22. */
  23. #include <boost/config.hpp> // put this first to suppress some VC++ warnings
  24. #include <iostream>
  25. #include <iterator>
  26. #include <algorithm>
  27. #include <time.h>
  28. #include <boost/utility.hpp>
  29. #include <boost/graph/adjacency_list.hpp>
  30. #include <boost/graph/topological_sort.hpp>
  31. #include <boost/graph/depth_first_search.hpp>
  32. #include <boost/graph/dijkstra_shortest_paths.hpp>
  33. #include <boost/graph/visitors.hpp>
  34. using namespace std;
  35. using namespace boost;
  36. enum files_e { dax_h, yow_h, boz_h, zow_h, foo_cpp,
  37. foo_o, bar_cpp, bar_o, libfoobar_a,
  38. zig_cpp, zig_o, zag_cpp, zag_o,
  39. libzigzag_a, killerapp, N };
  40. const char* name[] = { "dax.h", "yow.h", "boz.h", "zow.h", "foo.cpp",
  41. "foo.o", "bar.cpp", "bar.o", "libfoobar.a",
  42. "zig.cpp", "zig.o", "zag.cpp", "zag.o",
  43. "libzigzag.a", "killerapp" };
  44. struct print_visitor : public bfs_visitor<> {
  45. template <class Vertex, class Graph>
  46. void discover_vertex(Vertex v, Graph&) {
  47. cout << name[v] << " ";
  48. }
  49. };
  50. struct cycle_detector : public dfs_visitor<>
  51. {
  52. cycle_detector(bool& has_cycle)
  53. : m_has_cycle(has_cycle) { }
  54. template <class Edge, class Graph>
  55. void back_edge(Edge, Graph&) { m_has_cycle = true; }
  56. protected:
  57. bool& m_has_cycle;
  58. };
  59. int main(int,char*[])
  60. {
  61. typedef pair<int,int> Edge;
  62. Edge used_by[] = {
  63. Edge(dax_h, foo_cpp), Edge(dax_h, bar_cpp), Edge(dax_h, yow_h),
  64. Edge(yow_h, bar_cpp), Edge(yow_h, zag_cpp),
  65. Edge(boz_h, bar_cpp), Edge(boz_h, zig_cpp), Edge(boz_h, zag_cpp),
  66. Edge(zow_h, foo_cpp),
  67. Edge(foo_cpp, foo_o),
  68. Edge(foo_o, libfoobar_a),
  69. Edge(bar_cpp, bar_o),
  70. Edge(bar_o, libfoobar_a),
  71. Edge(libfoobar_a, libzigzag_a),
  72. Edge(zig_cpp, zig_o),
  73. Edge(zig_o, libzigzag_a),
  74. Edge(zag_cpp, zag_o),
  75. Edge(zag_o, libzigzag_a),
  76. Edge(libzigzag_a, killerapp)
  77. };
  78. const std::size_t nedges = sizeof(used_by)/sizeof(Edge);
  79. typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
  80. #if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
  81. // VC++ can't handle the iterator constructor
  82. Graph g(N);
  83. for (std::size_t j = 0; j < nedges; ++j) {
  84. graph_traits<Graph>::edge_descriptor e; bool inserted;
  85. boost::tie(e, inserted) = add_edge(used_by[j].first, used_by[j].second, g);
  86. }
  87. #else
  88. Graph g(used_by, used_by + nedges, N);
  89. #endif
  90. typedef graph_traits<Graph>::vertex_descriptor Vertex;
  91. // Determine ordering for a full recompilation
  92. // and the order with files that can be compiled in parallel
  93. {
  94. typedef list<Vertex> MakeOrder;
  95. MakeOrder::iterator i;
  96. MakeOrder make_order;
  97. topological_sort(g, std::front_inserter(make_order));
  98. cout << "make ordering: ";
  99. for (i = make_order.begin();
  100. i != make_order.end(); ++i)
  101. cout << name[*i] << " ";
  102. cout << endl << endl;
  103. // Parallel compilation ordering
  104. std::vector<int> time(N, 0);
  105. for (i = make_order.begin(); i != make_order.end(); ++i) {
  106. // Walk through the in_edges an calculate the maximum time.
  107. if (in_degree (*i, g) > 0) {
  108. Graph::in_edge_iterator j, j_end;
  109. int maxdist=0;
  110. // Through the order from topological sort, we are sure that every
  111. // time we are using here is already initialized.
  112. for (boost::tie(j, j_end) = in_edges(*i, g); j != j_end; ++j)
  113. maxdist=(std::max)(time[source(*j, g)], maxdist);
  114. time[*i]=maxdist+1;
  115. }
  116. }
  117. cout << "parallel make ordering, " << endl
  118. << "vertices with same group number can be made in parallel" << endl;
  119. {
  120. graph_traits<Graph>::vertex_iterator i, iend;
  121. for (boost::tie(i,iend) = vertices(g); i != iend; ++i)
  122. cout << "time_slot[" << name[*i] << "] = " << time[*i] << endl;
  123. }
  124. }
  125. cout << endl;
  126. // if I change yow.h what files need to be re-made?
  127. {
  128. cout << "A change to yow.h will cause what to be re-made?" << endl;
  129. print_visitor vis;
  130. breadth_first_search(g, vertex(yow_h, g), visitor(vis));
  131. cout << endl;
  132. }
  133. cout << endl;
  134. // are there any cycles in the graph?
  135. {
  136. bool has_cycle = false;
  137. cycle_detector vis(has_cycle);
  138. depth_first_search(g, visitor(vis));
  139. cout << "The graph has a cycle? " << has_cycle << endl;
  140. }
  141. cout << endl;
  142. // add a dependency going from bar.cpp to dax.h
  143. {
  144. cout << "adding edge bar_cpp -> dax_h" << endl;
  145. add_edge(bar_cpp, dax_h, g);
  146. }
  147. cout << endl;
  148. // are there any cycles in the graph?
  149. {
  150. bool has_cycle = false;
  151. cycle_detector vis(has_cycle);
  152. depth_first_search(g, visitor(vis));
  153. cout << "The graph has a cycle now? " << has_cycle << endl;
  154. }
  155. return 0;
  156. }