PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/package/boost_1_58_0/libs/graph/doc/file_dependency_example.html

https://gitlab.com/cdeclare/intcrypt
HTML | 363 lines | 310 code | 46 blank | 7 comment | 0 complexity | eee2959b23c3a6573843d9498ab78bc3 MD5 | raw file
  1. <HTML>
  2. <!--
  3. Copyright (c) Jeremy Siek 2000
  4. Distributed under the Boost Software License, Version 1.0.
  5. (See accompanying file LICENSE_1_0.txt or copy at
  6. http://www.boost.org/LICENSE_1_0.txt)
  7. -->
  8. <Head>
  9. <Title>File Dependency Example</Title>
  10. <BODY BGCOLOR="#ffffff" LINK="#0000ee" TEXT="#000000" VLINK="#551a8b"
  11. ALINK="#ff0000">
  12. <IMG SRC="../../../boost.png"
  13. ALT="C++ Boost" width="277" height="86">
  14. <BR Clear>
  15. <H1><A NAME="sec:file-depend-eg"></A>
  16. File Dependency Example
  17. </H1>
  18. <P>
  19. One of the most common uses of the graph abstraction in computer
  20. science is to track dependencies. An example of dependency tracking
  21. that we deal with on a day to day basis is the compilation
  22. dependencies for files in programs that we write. These dependencies
  23. are used inside programs such as <TT>make</TT> or in an IDE such as
  24. Visual C++ to minimize the number of files that must be recompiled
  25. after some changes have been made.
  26. <P>
  27. <A HREF="#fig:file-dep">Figure 1</A> shows a graph that has a vertex
  28. for each source file, object file, and library that is used in the
  29. <TT>killerapp</TT> program. The edges in the graph show which files
  30. are used in creating other files. The choice of which direction to
  31. point the arrows is somewhat arbitrary. As long as we are consistent
  32. in remembering that the arrows mean ``used by'' then things will work
  33. out. The opposite direction would mean ``depends on''.
  34. <P>
  35. <P></P>
  36. <DIV ALIGN="CENTER"><A NAME="fig:file-dep"></A>
  37. <TABLE>
  38. <CAPTION ALIGN="BOTTOM"><STRONG>Figure 1:</STRONG>
  39. A graph representing file dependencies.</CAPTION>
  40. <TR><TD><IMG SRC="./figs/file_dep.gif" width="331" height="351"></TD></TR>
  41. </TABLE>
  42. </DIV><P></P>
  43. <P>
  44. A compilation system such as <TT>make</TT> has to be able to answer a
  45. number of questions:
  46. <P>
  47. <OL>
  48. <LI>If we need to compile (or recompile) all of the files, what order
  49. should that be done it?
  50. </LI>
  51. <LI>What files can be compiled in parallel?
  52. </LI>
  53. <LI>If a file is changed, which files must be recompiled?
  54. </LI>
  55. <LI>Are there any cycles in the dependencies? (which means the user
  56. has made a mistake and an error should be emitted)
  57. </LI>
  58. </OL>
  59. <P>
  60. In the following examples we will formulate each of these questions in
  61. terms of the dependency graph, and then find a graph algorithm to
  62. provide the solution. The graph in <A HREF="#fig:file-dep">Figure
  63. 1</A> will be used in all of the following examples. The source code
  64. for this example can be found in the file <a
  65. href="../example/file_dependencies.cpp"><TT>examples/file_dependencies.cpp</TT></a>.
  66. <P>
  67. <H2>Graph Setup</H2>
  68. <P>
  69. Here we show the construction of the graph. First, these are the required
  70. header files:
  71. <P>
  72. <PRE>
  73. #include &lt;iostream&gt; // std::cout
  74. #include &lt;utility&gt; // std::pair
  75. #include &lt;boost/graph/graph_traits.hpp&gt;
  76. #include &lt;boost/graph/adjacency_list.hpp&gt;
  77. #include &lt;boost/graph/topological_sort.hpp&gt;
  78. </PRE>
  79. <P>
  80. For simplicity we have
  81. constructed the graph &quot;by-hand&quot;. A compilation system such
  82. as <TT>make</TT> would instead parse a <TT>Makefile</TT> to get the
  83. list of files and to set-up the dependencies. We use the
  84. <TT>adjacency_list</TT> class to represent the graph. The
  85. <TT>vecS</TT> selector means that a <TT>std::vector</TT> will be used
  86. to represent each edge-list, which provides efficient traversal. The
  87. <TT>bidirectionalS</TT> selector means we want a directed graph with access to both the edges outgoing from each vertex and the edges incoming to each vertex, and the
  88. <TT>color_property</TT> attaches a color property to each vertex of the
  89. graph. The color property will be used in several of the algorithms in
  90. the following sections.
  91. <P>
  92. <PRE>
  93. enum files_e { dax_h, yow_h, boz_h, zow_h, foo_cpp,
  94. foo_o, bar_cpp, bar_o, libfoobar_a,
  95. zig_cpp, zig_o, zag_cpp, zag_o,
  96. libzigzag_a, killerapp, N };
  97. const char* name[] = { "dax.h", "yow.h", "boz.h", "zow.h", "foo.cpp",
  98. "foo.o", "bar.cpp", "bar.o", "libfoobar.a",
  99. "zig.cpp", "zig.o", "zag.cpp", "zag.o",
  100. "libzigzag.a", "killerapp" };
  101. typedef std::pair&lt;int, int&gt; Edge;
  102. Edge used_by[] = {
  103. Edge(dax_h, foo_cpp), Edge(dax_h, bar_cpp), Edge(dax_h, yow_h),
  104. Edge(yow_h, bar_cpp), Edge(yow_h, zag_cpp),
  105. Edge(boz_h, bar_cpp), Edge(boz_h, zig_cpp), Edge(boz_h, zag_cpp),
  106. Edge(zow_h, foo_cpp),
  107. Edge(foo_cpp, foo_o),
  108. Edge(foo_o, libfoobar_a),
  109. Edge(bar_cpp, bar_o),
  110. Edge(bar_o, libfoobar_a),
  111. Edge(libfoobar_a, libzigzag_a),
  112. Edge(zig_cpp, zig_o),
  113. Edge(zig_o, libzigzag_a),
  114. Edge(zag_cpp, zag_o),
  115. Edge(zag_o, libzigzag_a),
  116. Edge(libzigzag_a, killerapp)
  117. };
  118. using namespace boost;
  119. typedef adjacency_list&lt;vecS, vecS, bidirectionalS,
  120. property&lt;vertex_color_t, default_color_type&gt;
  121. &gt; Graph;
  122. Graph g(used_by, used_by + sizeof(used_by) / sizeof(Edge), N);
  123. typedef graph_traits&lt;Graph&gt;::vertex_descriptor Vertex;
  124. </PRE>
  125. <P>
  126. <H2>Compilation Order (All Files)</H2>
  127. <P>
  128. On the first invocation of <TT>make</TT> for a particular project, all
  129. of the files must be compiled. Given the dependencies between the
  130. various files, what is the correct order in which to compile and link
  131. them? First we need to formulate this in terms of a graph. Finding a
  132. compilation order is the same as ordering the vertices in the graph.
  133. The constraint on the ordering is the file dependencies which we have
  134. represented as edges. So if there is an edge <i>(u,v)</i> in the graph
  135. then <i>v</i> better not come before <i>u</i> in the ordering. It
  136. turns out that this kind of constrained ordering is called a
  137. <I>topological sort</I>. Therefore, answering the question of
  138. compilation order is as easy as calling the BGL algorithm <a
  139. href="./topological_sort.html"><TT>topological_sort()</TT></a>. The
  140. traditional form of the output for topological sort is a linked-list
  141. of the sorted vertices. The BGL algorithm instead puts the sorted
  142. vertices into any <a
  143. href="http://www.sgi.com/tech/stl/OutputIterator.html">OutputIterator</a>,
  144. which allows for much more flexibility. Here we use the
  145. <TT>std::front_insert_iterator</TT> to create an output iterator that
  146. inserts the vertices on the front of a linked list. Other possible
  147. options are writing the output to a file or inserting into a different
  148. STL or custom-made container.
  149. <P>
  150. <PRE>
  151. typedef std::list&lt;Vertex&gt; MakeOrder;
  152. MakeOrder make_order;
  153. boost::topological_sort(g, std::front_inserter(make_order));
  154. std::cout &lt;&lt; "make ordering: ";
  155. for (MakeOrder::iterator i = make_order.begin();
  156. i != make_order.end(); ++i)
  157. std::cout &lt;&lt; name[*i] &lt;&lt; " ";
  158. std::cout &lt;&lt; std::endl;
  159. </PRE>
  160. The output of this is:
  161. <PRE>
  162. make ordering: zow.h boz.h zig.cpp zig.o dax.h yow.h zag.cpp \
  163. zag.o bar.cpp bar.o foo.cpp foo.o libfoobar.a libzigzag.a killerapp
  164. </PRE>
  165. <P>
  166. <H2><A NAME="sec:parallel-compilation"></A>
  167. Parallel Compilation
  168. </H2>
  169. <P>
  170. Another question the compilation system might need to answer is: what
  171. files can be compiled simultaneously? This would allow the system to
  172. spawn threads and utilize multiple processors to speed up the build.
  173. This question can also be put in a slightly different way: what is the
  174. earliest time that a file can be built assuming that an unlimited
  175. number of files can be built at the same time? The main criteria for
  176. when a file can be built is that all of the files it depends on must
  177. already be built. To simplify things for this example, we'll assume
  178. that each file takes 1 time unit to build (even header files). For
  179. parallel compilation, we can build all of the files corresponding to
  180. vertices with no dependencies, e.g., those that have
  181. an <i>in-degree</i> of 0, in the first step. For all other files, the
  182. main observation for determining the ``time slot'' for a file is that
  183. the time slot must be one more than the maximum time-slot of the files
  184. it depends on.
  185. <P>We start by creating a vector <code>time</code> that will store the
  186. time step at which each file can be built. We initialize every value
  187. with time step zero.</p>
  188. <P>
  189. <PRE>
  190. std::vector&lt;int&gt; time(N, 0);
  191. </PRE>
  192. <p>Now, we want to visit the vertices against in topological order,
  193. from those files that need to be built first until those that need
  194. to be built last. However, instead of printing out the order
  195. immediately, we will compute the time step in which each file should
  196. be built based on the time steps of the files it depends on. We
  197. only need to consider those files whose in-degree is greater than
  198. zero.</p>
  199. <pre>
  200. for (i = make_order.begin(); i != make_order.end(); ++i) {
  201. if (in_degree (*i, g) &gt; 0) {
  202. Graph::in_edge_iterator j, j_end;
  203. int maxdist = 0;
  204. for (boost::tie(j, j_end) = in_edges(*i, g); j != j_end; ++j)
  205. maxdist = std::max(time[source(*j, g)], maxdist);
  206. time[*i]=maxdist+1;
  207. }
  208. }
  209. </pre>
  210. <P>
  211. Last, we output the time-slot that we've calculated for each vertex.
  212. <P>
  213. <PRE>
  214. std::cout &lt;&lt; "parallel make ordering, " &lt;&lt; std::endl
  215. &lt;&lt; " vertices with same group number" &lt;&lt; std::endl
  216. &lt;&lt; " can be made in parallel" &lt;&lt; std::endl &lt;&lt; std::endl;
  217. for (boost::tie(i, iend) = vertices(g); i != iend; ++i)
  218. std::cout &lt;&lt; "time_slot[" &lt;&lt; name[*i] &lt;&lt; "] = " &lt;&lt; time[*i] &lt;&lt; std::endl;
  219. </PRE>
  220. The output is:
  221. <PRE>
  222. parallel make ordering,
  223. vertices with same group number
  224. can be made in parallel
  225. time_slot[dax.h] = 0
  226. time_slot[yow.h] = 1
  227. time_slot[boz.h] = 0
  228. time_slot[zow.h] = 0
  229. time_slot[foo.cpp] = 1
  230. time_slot[foo.o] = 2
  231. time_slot[bar.cpp] = 2
  232. time_slot[bar.o] = 3
  233. time_slot[libfoobar.a] = 4
  234. time_slot[zig.cpp] = 1
  235. time_slot[zig.o] = 2
  236. time_slot[zag.cpp] = 2
  237. time_slot[zag.o] = 3
  238. time_slot[libzigzag.a] = 5
  239. time_slot[killerapp] = 6
  240. </PRE>
  241. <P>
  242. <H2><A NAME="SECTION001014000000000000000"></A>
  243. <A NAME="sec:cycles"></A>
  244. <BR>
  245. Cyclic Dependencies
  246. </H2>
  247. <P>
  248. Another question the compilation system needs to be able to answer is
  249. whether there are any cycles in the dependencies. If there are cycles,
  250. the system will need to report an error to the user so that the cycles
  251. can be removed. One easy way to detect a cycle is to run a <a
  252. href="./depth_first_search.html">depth-first search</a>, and if the
  253. search runs into an already discovered vertex (of the current search
  254. tree), then there is a cycle. The BGL graph search algorithms (which
  255. includes
  256. <TT>depth_first_search()</TT>) are all extensible via the
  257. <I>visitor</I> mechanism. A visitor is similar to a function object,
  258. but it has several methods instead of just the one
  259. <TT>operator()</TT>. The visitor's methods are called at certain
  260. points within the algorithm, thereby giving the user a way to extend
  261. the functionality of the graph search algorithms. See Section <A
  262. HREF="visitor_concepts.html">Visitor Concepts</A>
  263. for a detailed description of visitors.
  264. <P>
  265. We will create a visitor class and fill in the <TT>back_edge()</TT>
  266. method, which is the <a href="./DFSVisitor.html">DFSVisitor</a> method
  267. that is called when DFS explores an edge to an already discovered
  268. vertex. A call to this method indicates the existence of a
  269. cycle. Inheriting from <TT>dfs_visitor&lt;&gt;</TT>
  270. provides the visitor with empty versions of the other visitor methods.
  271. Once our visitor is created, we can construct and object and pass it
  272. to the BGL algorithm. Visitor objects are passed by value inside of
  273. the BGL algorithms, so the <TT>has_cycle</TT> flag is stored by
  274. reference in this visitor.
  275. <P>
  276. <PRE>
  277. struct cycle_detector : public dfs_visitor&lt;&gt;
  278. {
  279. cycle_detector( bool&amp; has_cycle)
  280. : _has_cycle(has_cycle) { }
  281. template &lt;class Edge, class Graph&gt;
  282. void back_edge(Edge, Graph&amp;) {
  283. _has_cycle = true;
  284. }
  285. protected:
  286. bool&amp; _has_cycle;
  287. };
  288. </PRE>
  289. <P>
  290. We can now invoke the BGL <TT>depth_first_search()</TT>
  291. algorithm and pass in the cycle detector visitor.
  292. <P>
  293. <PRE>
  294. bool has_cycle = false;
  295. cycle_detector vis(has_cycle);
  296. boost::depth_first_search(g, visitor(vis));
  297. std::cout &lt;&lt; "The graph has a cycle? " &lt;&lt; has_cycle &lt;&lt; std::endl;
  298. </PRE>
  299. <P>
  300. The graph in <A HREF="#fig:file-dep">Figure 1</A> (ignoring the dotted
  301. line) did not have any cycles, but if we add a dependency between
  302. <TT>bar.cpp</TT> and <TT>dax.h</TT> there there will be. Such a
  303. dependency would be flagged as a user error.
  304. <P>
  305. <PRE>
  306. add_edge(bar_cpp, dax_h, g);
  307. </PRE>
  308. <br>
  309. <HR>
  310. <TABLE>
  311. <TR valign=top>
  312. <TD nowrap>Copyright &copy; 2000-2001</TD><TD>
  313. <A HREF="http://www.boost.org/people/jeremy_siek.htm">Jeremy Siek</A>, Indiana University (<A HREF="mailto:jsiek@osl.iu.edu">jsiek@osl.iu.edu</A>)
  314. </TD></TR></TABLE>
  315. </BODY>
  316. </HTML>