]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/boostdep/src/boostdep.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / boostdep / src / boostdep.cpp
1
2 // boostdep - a tool to generate Boost dependency reports
3 //
4 // Copyright 2014-2017 Peter Dimov
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt
9
10
11 #include <boost/filesystem.hpp>
12 #include <boost/filesystem/fstream.hpp>
13 #include <string>
14 #include <iostream>
15 #include <fstream>
16 #include <vector>
17 #include <map>
18 #include <set>
19 #include <algorithm>
20 #include <climits>
21
22 namespace fs = boost::filesystem;
23
24 // header -> module
25 static std::map< std::string, std::string > s_header_map;
26
27 // module -> headers
28 static std::map< std::string, std::set<std::string> > s_module_headers;
29
30 static std::set< std::string > s_modules;
31
32 static void scan_module_headers( fs::path const & path )
33 {
34 try
35 {
36 std::string module = path.generic_string().substr( 5 ); // strip "libs/"
37
38 std::replace( module.begin(), module.end(), '/', '~' );
39
40 s_modules.insert( module );
41
42 fs::path dir = path / "include";
43 size_t n = dir.generic_string().size();
44
45 fs::recursive_directory_iterator it( dir ), last;
46
47 for( ; it != last; ++it )
48 {
49 if( it->status().type() == fs::directory_file )
50 {
51 continue;
52 }
53
54 std::string p2 = it->path().generic_string();
55 p2 = p2.substr( n+1 );
56
57 s_header_map[ p2 ] = module;
58 s_module_headers[ module ].insert( p2 );
59 }
60 }
61 catch( fs::filesystem_error const & x )
62 {
63 std::cout << x.what() << std::endl;
64 }
65 }
66
67 static void scan_submodules( fs::path const & path )
68 {
69 fs::directory_iterator it( path ), last;
70
71 for( ; it != last; ++it )
72 {
73 fs::directory_entry const & e = *it;
74
75 if( e.status().type() != fs::directory_file )
76 {
77 continue;
78 }
79
80 fs::path path = e.path();
81
82 if( fs::exists( path / "include" ) )
83 {
84 scan_module_headers( path );
85 }
86
87 if( fs::exists( path / "sublibs" ) )
88 {
89 scan_submodules( path );
90 }
91 }
92 }
93
94 static void build_header_map()
95 {
96 scan_submodules( "libs" );
97 }
98
99 static void scan_header_dependencies( std::string const & header, std::istream & is, std::map< std::string, std::set< std::string > > & deps, std::map< std::string, std::set< std::string > > & from )
100 {
101 std::string line;
102
103 while( std::getline( is, line ) )
104 {
105 while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
106 {
107 line.erase( 0, 1 );
108 }
109
110 if( line.empty() || line[0] != '#' ) continue;
111
112 line.erase( 0, 1 );
113
114 while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
115 {
116 line.erase( 0, 1 );
117 }
118
119 if( line.substr( 0, 7 ) != "include" ) continue;
120
121 line.erase( 0, 7 );
122
123 while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
124 {
125 line.erase( 0, 1 );
126 }
127
128 if( line.size() < 2 ) continue;
129
130 char ch = line[0];
131
132 if( ch != '<' && ch != '"' ) continue;
133
134 if( ch == '<' )
135 {
136 ch = '>';
137 }
138
139 line.erase( 0, 1 );
140
141 std::string::size_type k = line.find_first_of( ch );
142
143 if( k != std::string::npos )
144 {
145 line.erase( k );
146 }
147
148 std::map< std::string, std::string >::const_iterator i = s_header_map.find( line );
149
150 if( i != s_header_map.end() )
151 {
152 deps[ i->second ].insert( line );
153 from[ line ].insert( header );
154 }
155 else if( line.substr( 0, 6 ) == "boost/" )
156 {
157 deps[ "(unknown)" ].insert( line );
158 from[ line ].insert( header );
159 }
160 }
161 }
162
163 struct module_primary_actions
164 {
165 virtual void heading( std::string const & module ) = 0;
166
167 virtual void module_start( std::string const & module ) = 0;
168 virtual void module_end( std::string const & module ) = 0;
169
170 virtual void header_start( std::string const & header ) = 0;
171 virtual void header_end( std::string const & header ) = 0;
172
173 virtual void from_header( std::string const & header ) = 0;
174 };
175
176 static fs::path module_include_path( std::string module )
177 {
178 std::replace( module.begin(), module.end(), '~', '/' );
179 return fs::path( "libs" ) / module / "include";
180 }
181
182 static fs::path module_source_path( std::string module )
183 {
184 std::replace( module.begin(), module.end(), '~', '/' );
185 return fs::path( "libs" ) / module / "src";
186 }
187
188 static fs::path module_build_path( std::string module )
189 {
190 std::replace( module.begin(), module.end(), '~', '/' );
191 return fs::path( "libs" ) / module / "build";
192 }
193
194 static fs::path module_test_path( std::string module )
195 {
196 std::replace( module.begin(), module.end(), '~', '/' );
197 return fs::path( "libs" ) / module / "test";
198 }
199
200 static void scan_module_path( fs::path const & dir, bool remove_prefix, std::map< std::string, std::set< std::string > > & deps, std::map< std::string, std::set< std::string > > & from )
201 {
202 size_t n = dir.generic_string().size();
203
204 if( fs::exists( dir ) )
205 {
206 fs::recursive_directory_iterator it( dir ), last;
207
208 for( ; it != last; ++it )
209 {
210 if( it->status().type() == fs::directory_file )
211 {
212 continue;
213 }
214
215 std::string header = it->path().generic_string();
216
217 if( remove_prefix )
218 {
219 header = header.substr( n+1 );
220 }
221
222 fs::ifstream is( it->path() );
223
224 scan_header_dependencies( header, is, deps, from );
225 }
226 }
227 }
228
229 static void scan_module_dependencies( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests, bool include_self )
230 {
231 // module -> [ header, header... ]
232 std::map< std::string, std::set< std::string > > deps;
233
234 // header -> included from [ header, header... ]
235 std::map< std::string, std::set< std::string > > from;
236
237 scan_module_path( module_include_path( module ), true, deps, from );
238
239 if( track_sources )
240 {
241 scan_module_path( module_source_path( module ), false, deps, from );
242 }
243
244 if( track_tests )
245 {
246 scan_module_path( module_test_path( module ), false, deps, from );
247 }
248
249 actions.heading( module );
250
251 for( std::map< std::string, std::set< std::string > >::iterator i = deps.begin(); i != deps.end(); ++i )
252 {
253 if( i->first == module && !include_self ) continue;
254
255 actions.module_start( i->first );
256
257 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
258 {
259 actions.header_start( *j );
260
261 std::set< std::string > const & f = from[ *j ];
262
263 for( std::set< std::string >::const_iterator k = f.begin(); k != f.end(); ++k )
264 {
265 actions.from_header( *k );
266 }
267
268 actions.header_end( *j );
269 }
270
271 actions.module_end( i->first );
272 }
273 }
274
275 // module depends on [ module, module... ]
276 static std::map< std::string, std::set< std::string > > s_module_deps;
277
278 // header is included by [header, header...]
279 static std::map< std::string, std::set< std::string > > s_header_deps;
280
281 // [ module, module... ] depend on module
282 static std::map< std::string, std::set< std::string > > s_reverse_deps;
283
284 // header includes [header, header...]
285 static std::map< std::string, std::set< std::string > > s_header_includes;
286
287 struct build_mdmap_actions: public module_primary_actions
288 {
289 std::string module_;
290 std::string module2_;
291 std::string header_;
292
293 void heading( std::string const & module )
294 {
295 module_ = module;
296 }
297
298 void module_start( std::string const & module )
299 {
300 if( module != module_ )
301 {
302 s_module_deps[ module_ ].insert( module );
303 s_reverse_deps[ module ].insert( module_ );
304 }
305
306 module2_ = module;
307 }
308
309 void module_end( std::string const & /*module*/ )
310 {
311 }
312
313 void header_start( std::string const & header )
314 {
315 header_ = header;
316 }
317
318 void header_end( std::string const & /*header*/ )
319 {
320 }
321
322 void from_header( std::string const & header )
323 {
324 if( module_ != module2_ )
325 {
326 s_header_deps[ header_ ].insert( header );
327 }
328
329 s_header_includes[ header ].insert( header_ );
330 }
331 };
332
333 static void build_module_dependency_map( bool track_sources, bool track_tests )
334 {
335 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
336 {
337 build_mdmap_actions actions;
338 scan_module_dependencies( *i, actions, track_sources, track_tests, true );
339 }
340 }
341
342 static void output_module_primary_report( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests )
343 {
344 try
345 {
346 scan_module_dependencies( module, actions, track_sources, track_tests, false );
347 }
348 catch( fs::filesystem_error const & x )
349 {
350 std::cout << x.what() << std::endl;
351 }
352 }
353
354 struct module_secondary_actions
355 {
356 virtual void heading( std::string const & module ) = 0;
357
358 virtual void module_start( std::string const & module ) = 0;
359 virtual void module_end( std::string const & module ) = 0;
360
361 virtual void module_adds( std::string const & module ) = 0;
362 };
363
364 static void exclude( std::set< std::string > & x, std::set< std::string > const & y )
365 {
366 for( std::set< std::string >::const_iterator i = y.begin(); i != y.end(); ++i )
367 {
368 x.erase( *i );
369 }
370 }
371
372 static void output_module_secondary_report( std::string const & module, std::set< std::string> deps, module_secondary_actions & actions )
373 {
374 actions.heading( module );
375
376 deps.insert( module );
377
378 // build transitive closure
379
380 for( ;; )
381 {
382 std::set< std::string > deps2( deps );
383
384 for( std::set< std::string >::iterator i = deps.begin(); i != deps.end(); ++i )
385 {
386 std::set< std::string > deps3 = s_module_deps[ *i ];
387
388 exclude( deps3, deps );
389
390 if( deps3.empty() )
391 {
392 continue;
393 }
394
395 actions.module_start( *i );
396
397 for( std::set< std::string >::iterator j = deps3.begin(); j != deps3.end(); ++j )
398 {
399 actions.module_adds( *j );
400 }
401
402 actions.module_end( *i );
403
404 deps2.insert( deps3.begin(), deps3.end() );
405 }
406
407 if( deps == deps2 )
408 {
409 break;
410 }
411 else
412 {
413 deps = deps2;
414 }
415 }
416 }
417
418 static void output_module_secondary_report( std::string const & module, module_secondary_actions & actions )
419 {
420 output_module_secondary_report( module, s_module_deps[ module ], actions );
421 }
422
423 struct header_inclusion_actions
424 {
425 virtual void heading( std::string const & header, std::string const & module ) = 0;
426
427 virtual void module_start( std::string const & module ) = 0;
428 virtual void module_end( std::string const & module ) = 0;
429
430 virtual void header( std::string const & header ) = 0;
431 };
432
433 static void output_header_inclusion_report( std::string const & header, header_inclusion_actions & actions )
434 {
435 std::string module = s_header_map[ header ];
436
437 actions.heading( header, module );
438
439 std::set< std::string > from = s_header_deps[ header ];
440
441 // classify 'from' dependencies by module
442
443 // module -> [header, header...]
444 std::map< std::string, std::set< std::string > > from2;
445
446 for( std::set< std::string >::iterator i = from.begin(); i != from.end(); ++i )
447 {
448 from2[ s_header_map[ *i ] ].insert( *i );
449 }
450
451 for( std::map< std::string, std::set< std::string > >::iterator i = from2.begin(); i != from2.end(); ++i )
452 {
453 actions.module_start( i->first );
454
455 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
456 {
457 actions.header( *j );
458 }
459
460 actions.module_end( i->first );
461 }
462 }
463
464 // output_module_primary_report
465
466 struct module_primary_txt_actions: public module_primary_actions
467 {
468 void heading( std::string const & module )
469 {
470 std::cout << "Primary dependencies for " << module << ":\n\n";
471 }
472
473 void module_start( std::string const & module )
474 {
475 std::cout << module << ":\n";
476 }
477
478 void module_end( std::string const & /*module*/ )
479 {
480 std::cout << "\n";
481 }
482
483 void header_start( std::string const & header )
484 {
485 std::cout << " <" << header << ">\n";
486 }
487
488 void header_end( std::string const & /*header*/ )
489 {
490 }
491
492 void from_header( std::string const & header )
493 {
494 std::cout << " from <" << header << ">\n";
495 }
496 };
497
498 struct module_primary_html_actions: public module_primary_actions
499 {
500 void heading( std::string const & module )
501 {
502 std::cout << "\n\n<h1 id=\"primary-dependencies\">Primary dependencies for <em>" << module << "</em></h1>\n";
503 }
504
505 void module_start( std::string const & module )
506 {
507 std::cout << " <h2 id=\"" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2>\n";
508 }
509
510 void module_end( std::string const & /*module*/ )
511 {
512 }
513
514 void header_start( std::string const & header )
515 {
516 std::cout << " <h3><code>&lt;" << header << "&gt;</code></h3><ul>\n";
517 }
518
519 void header_end( std::string const & /*header*/ )
520 {
521 std::cout << " </ul>\n";
522 }
523
524 void from_header( std::string const & header )
525 {
526 std::cout << " <li>from <code>&lt;" << header << "&gt;</code></li>\n";
527 }
528 };
529
530 static void output_module_primary_report( std::string const & module, bool html, bool track_sources, bool track_tests )
531 {
532 if( html )
533 {
534 module_primary_html_actions actions;
535 output_module_primary_report( module, actions, track_sources, track_tests );
536 }
537 else
538 {
539 module_primary_txt_actions actions;
540 output_module_primary_report( module, actions, track_sources, track_tests );
541 }
542 }
543
544 // output_module_secondary_report
545
546 struct module_secondary_txt_actions: public module_secondary_actions
547 {
548 void heading( std::string const & module )
549 {
550 std::cout << "Secondary dependencies for " << module << ":\n\n";
551 }
552
553 void module_start( std::string const & module )
554 {
555 std::cout << module << ":\n";
556 }
557
558 void module_end( std::string const & /*module*/ )
559 {
560 std::cout << "\n";
561 }
562
563 void module_adds( std::string const & module )
564 {
565 std::cout << " adds " << module << "\n";
566 }
567 };
568
569 struct module_secondary_html_actions: public module_secondary_actions
570 {
571 std::string m2_;
572
573 void heading( std::string const & module )
574 {
575 std::cout << "\n\n<h1 id=\"secondary-dependencies\">Secondary dependencies for <em>" << module << "</em></h1>\n";
576 }
577
578 void module_start( std::string const & module )
579 {
580 std::cout << " <h2><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
581 m2_ = module;
582 }
583
584 void module_end( std::string const & /*module*/ )
585 {
586 std::cout << " </ul>\n";
587 }
588
589 void module_adds( std::string const & module )
590 {
591 std::cout << " <li><a href=\"" << m2_ << ".html#" << module << "\">adds <em>" << module << "</em></a></li>\n";
592 }
593 };
594
595 static void output_module_secondary_report( std::string const & module, bool html )
596 {
597 if( html )
598 {
599 module_secondary_html_actions actions;
600 output_module_secondary_report( module, actions );
601 }
602 else
603 {
604 module_secondary_txt_actions actions;
605 output_module_secondary_report( module, actions );
606 }
607 }
608
609 // output_header_report
610
611 struct header_inclusion_txt_actions: public header_inclusion_actions
612 {
613 void heading( std::string const & header, std::string const & module )
614 {
615 std::cout << "Inclusion report for <" << header << "> (in module " << module << "):\n\n";
616 }
617
618 void module_start( std::string const & module )
619 {
620 std::cout << " from " << module << ":\n";
621 }
622
623 void module_end( std::string const & /*module*/ )
624 {
625 std::cout << "\n";
626 }
627
628 void header( std::string const & header )
629 {
630 std::cout << " <" << header << ">\n";
631 }
632 };
633
634 struct header_inclusion_html_actions: public header_inclusion_actions
635 {
636 void heading( std::string const & header, std::string const & module )
637 {
638 std::cout << "<h1>Inclusion report for <code>&lt;" << header << "&gt;</code> (in module <em>" << module << "</em>)</h1>\n";
639 }
640
641 void module_start( std::string const & module )
642 {
643 std::cout << " <h2>From <a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
644 }
645
646 void module_end( std::string const & /*module*/ )
647 {
648 std::cout << " </ul>\n";
649 }
650
651 void header( std::string const & header )
652 {
653 std::cout << " <li><code>&lt;" << header << "&gt;</code></li>\n";
654 }
655 };
656
657 static void output_header_report( std::string const & header, bool html )
658 {
659 if( html )
660 {
661 header_inclusion_html_actions actions;
662 output_header_inclusion_report( header, actions );
663 }
664 else
665 {
666 header_inclusion_txt_actions actions;
667 output_header_inclusion_report( header, actions );
668 }
669 }
670
671 // output_module_reverse_report
672
673 struct module_reverse_actions
674 {
675 virtual void heading( std::string const & module ) = 0;
676
677 virtual void module_start( std::string const & module ) = 0;
678 virtual void module_end( std::string const & module ) = 0;
679
680 virtual void header_start( std::string const & header ) = 0;
681 virtual void header_end( std::string const & header ) = 0;
682
683 virtual void from_header( std::string const & header ) = 0;
684 };
685
686 static void output_module_reverse_report( std::string const & module, module_reverse_actions & actions )
687 {
688 actions.heading( module );
689
690 std::set< std::string > const from = s_reverse_deps[ module ];
691
692 for( std::set< std::string >::const_iterator i = from.begin(); i != from.end(); ++i )
693 {
694 actions.module_start( *i );
695
696 for( std::map< std::string, std::set< std::string > >::iterator j = s_header_deps.begin(); j != s_header_deps.end(); ++j )
697 {
698 if( s_header_map[ j->first ] == module )
699 {
700 bool header_started = false;
701
702 for( std::set< std::string >::iterator k = j->second.begin(); k != j->second.end(); ++k )
703 {
704 if( s_header_map[ *k ] == *i )
705 {
706 if( !header_started )
707 {
708 actions.header_start( j->first );
709
710 header_started = true;
711 }
712
713 actions.from_header( *k );
714 }
715 }
716
717 if( header_started )
718 {
719 actions.header_end( j->first );
720 }
721 }
722 }
723
724 actions.module_end( *i );
725 }
726 }
727
728 struct module_reverse_txt_actions: public module_reverse_actions
729 {
730 void heading( std::string const & module )
731 {
732 std::cout << "Reverse dependencies for " << module << ":\n\n";
733 }
734
735 void module_start( std::string const & module )
736 {
737 std::cout << module << ":\n";
738 }
739
740 void module_end( std::string const & /*module*/ )
741 {
742 std::cout << "\n";
743 }
744
745 void header_start( std::string const & header )
746 {
747 std::cout << " <" << header << ">\n";
748 }
749
750 void header_end( std::string const & /*header*/ )
751 {
752 }
753
754 void from_header( std::string const & header )
755 {
756 std::cout << " from <" << header << ">\n";
757 }
758 };
759
760 struct module_reverse_html_actions: public module_reverse_actions
761 {
762 void heading( std::string const & module )
763 {
764 std::cout << "\n\n<h1 id=\"reverse-dependencies\">Reverse dependencies for <em>" << module << "</em></h1>\n";
765 }
766
767 void module_start( std::string const & module )
768 {
769 std::cout << " <h2 id=\"reverse-" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2>\n";
770 }
771
772 void module_end( std::string const & /*module*/ )
773 {
774 }
775
776 void header_start( std::string const & header )
777 {
778 std::cout << " <h3><code>&lt;" << header << "&gt;</code></h3><ul>\n";
779 }
780
781 void header_end( std::string const & /*header*/ )
782 {
783 std::cout << " </ul>\n";
784 }
785
786 void from_header( std::string const & header )
787 {
788 std::cout << " <li>from <code>&lt;" << header << "&gt;</code></li>\n";
789 }
790 };
791
792 static void output_module_reverse_report( std::string const & module, bool html )
793 {
794 if( html )
795 {
796 module_reverse_html_actions actions;
797 output_module_reverse_report( module, actions );
798 }
799 else
800 {
801 module_reverse_txt_actions actions;
802 output_module_reverse_report( module, actions );
803 }
804 }
805
806 // module_level_report
807
808 int const unknown_level = INT_MAX / 2;
809
810 struct module_level_actions
811 {
812 virtual void begin() = 0;
813 virtual void end() = 0;
814
815 virtual void level_start( int level ) = 0;
816 virtual void level_end( int level ) = 0;
817
818 virtual void module_start( std::string const & module ) = 0;
819 virtual void module_end( std::string const & module ) = 0;
820
821 virtual void module2( std::string const & module, int level ) = 0;
822 };
823
824 static void output_module_level_report( module_level_actions & actions )
825 {
826 // build module level map
827
828 std::map< std::string, int > level_map;
829
830 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
831 {
832 if( s_module_deps[ *i ].empty() )
833 {
834 level_map[ *i ] = 0;
835 // std::cerr << *i << ": " << 0 << std::endl;
836 }
837 else
838 {
839 level_map[ *i ] = unknown_level;
840 }
841 }
842
843 // build transitive closure to see through cycles
844
845 std::map< std::string, std::set< std::string > > deps2 = s_module_deps;
846
847 {
848 bool done;
849
850 do
851 {
852 done = true;
853
854 for( std::map< std::string, std::set< std::string > >::iterator i = deps2.begin(); i != deps2.end(); ++i )
855 {
856 std::set< std::string > tmp = i->second;
857
858 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
859 {
860 std::set< std::string > tmp2 = deps2[ *j ];
861 tmp.insert( tmp2.begin(), tmp2.end() );
862 }
863
864 if( tmp.size() != i->second.size() )
865 {
866 i->second = tmp;
867 done = false;
868 }
869 }
870 }
871 while( !done );
872 }
873
874 // compute acyclic levels
875
876 for( int k = 1, n = s_modules.size(); k < n; ++k )
877 {
878 for( std::map< std::string, std::set< std::string > >::iterator i = s_module_deps.begin(); i != s_module_deps.end(); ++i )
879 {
880 // i->first depends on i->second
881
882 if( level_map[ i->first ] >= unknown_level )
883 {
884 int level = 0;
885
886 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
887 {
888 level = std::max( level, level_map[ *j ] + 1 );
889 }
890
891 if( level == k )
892 {
893 level_map[ i->first ] = level;
894 // std::cerr << i->first << ": " << level << std::endl;
895 }
896 }
897 }
898 }
899
900 // min_level_map[ M ] == L means the level is unknown, but at least L
901 std::map< std::string, int > min_level_map;
902
903 // initialize min_level_map for acyclic dependencies
904
905 for( std::map< std::string, int >::iterator i = level_map.begin(); i != level_map.end(); ++i )
906 {
907 if( i->second < unknown_level )
908 {
909 min_level_map[ i->first ] = i->second;
910 }
911 }
912
913 // compute levels for cyclic modules
914
915 for( int k = 1, n = s_modules.size(); k < n; ++k )
916 {
917 for( std::map< std::string, std::set< std::string > >::iterator i = s_module_deps.begin(); i != s_module_deps.end(); ++i )
918 {
919 if( level_map[ i->first ] >= unknown_level )
920 {
921 int level = 0;
922
923 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
924 {
925 int jl = level_map[ *j ];
926
927 if( jl < unknown_level )
928 {
929 level = std::max( level, jl + 1 );
930 }
931 else
932 {
933 int ml = min_level_map[ *j ];
934
935 if( deps2[ *j ].count( i->first ) == 0 )
936 {
937 // *j does not depend on i->first, so
938 // the level of i->first is at least
939 // 1 + the minimum level of *j
940
941 ++ml;
942 }
943
944 level = std::max( level, ml );
945 }
946 }
947
948 min_level_map[ i->first ] = level;
949 }
950 }
951 }
952
953 // reverse level map
954
955 std::map< int, std::set< std::string > > reverse_level_map;
956
957 for( std::map< std::string, int >::iterator i = level_map.begin(); i != level_map.end(); ++i )
958 {
959 int level = i->second;
960
961 if( level >= unknown_level )
962 {
963 int min_level = min_level_map[ i->first ];
964
965 if( min_level != 0 )
966 {
967 level = min_level;
968 }
969 }
970
971 reverse_level_map[ level ].insert( i->first );
972 }
973
974 // output report
975
976 actions.begin();
977
978 for( std::map< int, std::set< std::string > >::iterator i = reverse_level_map.begin(); i != reverse_level_map.end(); ++i )
979 {
980 actions.level_start( i->first );
981
982 for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
983 {
984 actions.module_start( *j );
985
986 std::set< std::string > mdeps = s_module_deps[ *j ];
987
988 for( std::set< std::string >::iterator k = mdeps.begin(); k != mdeps.end(); ++k )
989 {
990 int level = level_map[ *k ];
991
992 if( level >= unknown_level )
993 {
994 int min_level = min_level_map[ *k ];
995
996 if( min_level != 0 )
997 {
998 level = min_level;
999 }
1000 }
1001
1002 actions.module2( *k, level );
1003 }
1004
1005 actions.module_end( *j );
1006 }
1007
1008 actions.level_end( i->first );
1009 }
1010
1011 actions.end();
1012 }
1013
1014 struct module_level_txt_actions: public module_level_actions
1015 {
1016 int level_;
1017
1018 void begin()
1019 {
1020 std::cout << "Module Levels:\n\n";
1021 }
1022
1023 void end()
1024 {
1025 }
1026
1027 void level_start( int level )
1028 {
1029 if( level >= unknown_level )
1030 {
1031 std::cout << "Level (undetermined):\n";
1032 }
1033 else
1034 {
1035 std::cout << "Level " << level << ":\n";
1036 }
1037
1038 level_ = level;
1039 }
1040
1041 void level_end( int /*level*/ )
1042 {
1043 std::cout << "\n";
1044 }
1045
1046 void module_start( std::string const & module )
1047 {
1048 std::cout << " " << module;
1049
1050 if( level_ > 0 )
1051 {
1052 std::cout << " ->";
1053 }
1054 }
1055
1056 void module_end( std::string const & /*module*/ )
1057 {
1058 std::cout << "\n";
1059 }
1060
1061 void module2( std::string const & module, int level )
1062 {
1063 std::cout << " " << module << "(";
1064
1065 if( level >= unknown_level )
1066 {
1067 std::cout << "-";
1068 }
1069 else
1070 {
1071 std::cout << level;
1072 }
1073
1074 std::cout << ")";
1075 }
1076 };
1077
1078 struct module_level_html_actions: public module_level_actions
1079 {
1080 int level_;
1081
1082 void begin()
1083 {
1084 std::cout << "<div id='module-levels'><h1>Module Levels</h1>\n";
1085 }
1086
1087 void end()
1088 {
1089 std::cout << "</div>\n";
1090 }
1091
1092 void level_start( int level )
1093 {
1094 if( level >= unknown_level )
1095 {
1096 std::cout << " <h2>Level <em>undetermined</em></h2>\n";
1097 }
1098 else
1099 {
1100 std::cout << " <h2 id='level:" << level << "'>Level " << level << "</h2>\n";
1101 }
1102
1103 level_ = level;
1104 }
1105
1106 void level_end( int /*level*/ )
1107 {
1108 }
1109
1110 void module_start( std::string const & module )
1111 {
1112 std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3><p class='primary-list'>";
1113 }
1114
1115 void module_end( std::string const & /*module*/ )
1116 {
1117 std::cout << "</p>\n";
1118 }
1119
1120 void module2( std::string const & module, int level )
1121 {
1122 std::cout << " ";
1123
1124 bool important = level < unknown_level && level > 1 && level >= level_ - 1;
1125
1126 if( important )
1127 {
1128 std::cout << "<strong>";
1129 }
1130
1131 std::cout << module;
1132
1133 if( level < unknown_level )
1134 {
1135 std::cout << "<sup>" << level << "</sup>";
1136 }
1137
1138 if( important )
1139 {
1140 std::cout << "</strong>";
1141 }
1142 }
1143 };
1144
1145 static void output_module_level_report( bool html )
1146 {
1147 if( html )
1148 {
1149 module_level_html_actions actions;
1150 output_module_level_report( actions );
1151 }
1152 else
1153 {
1154 module_level_txt_actions actions;
1155 output_module_level_report( actions );
1156 }
1157 }
1158
1159 // module_overview_report
1160
1161 struct module_overview_actions
1162 {
1163 virtual void begin() = 0;
1164 virtual void end() = 0;
1165
1166 virtual void module_start( std::string const & module ) = 0;
1167 virtual void module_end( std::string const & module ) = 0;
1168
1169 virtual void module2( std::string const & module ) = 0;
1170 };
1171
1172 static void output_module_overview_report( module_overview_actions & actions )
1173 {
1174 actions.begin();
1175
1176 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1177 {
1178 actions.module_start( *i );
1179
1180 std::set< std::string > const mdeps = s_module_deps[ *i ];
1181
1182 for( std::set< std::string >::const_iterator j = mdeps.begin(); j != mdeps.end(); ++j )
1183 {
1184 actions.module2( *j );
1185 }
1186
1187 actions.module_end( *i );
1188 }
1189
1190 actions.end();
1191 }
1192
1193 struct module_overview_txt_actions: public module_overview_actions
1194 {
1195 bool deps_;
1196
1197 void begin()
1198 {
1199 std::cout << "Module Overview:\n\n";
1200 }
1201
1202 void end()
1203 {
1204 }
1205
1206 void module_start( std::string const & module )
1207 {
1208 std::cout << module;
1209 deps_ = false;
1210 }
1211
1212 void module_end( std::string const & /*module*/ )
1213 {
1214 std::cout << "\n";
1215 }
1216
1217 void module2( std::string const & module )
1218 {
1219 if( !deps_ )
1220 {
1221 std::cout << " ->";
1222 deps_ = true;
1223 }
1224
1225 std::cout << " " << module;
1226 }
1227 };
1228
1229 struct module_overview_html_actions: public module_overview_actions
1230 {
1231 void begin()
1232 {
1233 std::cout << "<div id='module-overview'><h1>Module Overview</h1>\n";
1234 }
1235
1236 void end()
1237 {
1238 std::cout << "</div>\n";
1239 }
1240
1241 void module_start( std::string const & module )
1242 {
1243 std::cout << " <h2 id='" << module << "'><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><p class='primary-list'>";
1244 }
1245
1246 void module_end( std::string const & /*module*/ )
1247 {
1248 std::cout << "</p>\n";
1249 }
1250
1251 void module2( std::string const & module )
1252 {
1253 std::cout << " " << module;
1254 }
1255 };
1256
1257 static void output_module_overview_report( bool html )
1258 {
1259 if( html )
1260 {
1261 module_overview_html_actions actions;
1262 output_module_overview_report( actions );
1263 }
1264 else
1265 {
1266 module_overview_txt_actions actions;
1267 output_module_overview_report( actions );
1268 }
1269 }
1270
1271 // list_dependencies
1272
1273 struct list_dependencies_actions: public module_overview_actions
1274 {
1275 void begin()
1276 {
1277 }
1278
1279 void end()
1280 {
1281 }
1282
1283 void module_start( std::string const & module )
1284 {
1285 std::cout << module << " ->";
1286 }
1287
1288 void module_end( std::string const & /*module*/ )
1289 {
1290 std::cout << "\n";
1291 }
1292
1293 void module2( std::string const & module )
1294 {
1295 if( module != "(unknown)" )
1296 {
1297 std::cout << " " << module;
1298 }
1299 }
1300 };
1301
1302 static void list_dependencies()
1303 {
1304 list_dependencies_actions actions;
1305 output_module_overview_report( actions );
1306 }
1307
1308 //
1309
1310 static void output_html_header( std::string const & title, std::string const & stylesheet, std::string const & prefix )
1311 {
1312 std::cout << "<html>\n";
1313 std::cout << "<head>\n";
1314 std::cout << "<title>" << title << "</title>\n";
1315
1316 if( !stylesheet.empty() )
1317 {
1318 std::cout << "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet << "\" />\n";
1319 }
1320
1321 std::cout << "</head>\n";
1322 std::cout << "<body>\n";
1323
1324 if( !prefix.empty() )
1325 {
1326 std::cout << prefix << std::endl;
1327 }
1328 }
1329
1330 static void output_html_footer( std::string const & footer )
1331 {
1332 std::cout << "<hr />\n";
1333 std::cout << "<p class=\"footer\">" << footer << "</p>\n";
1334 std::cout << "</body>\n";
1335 std::cout << "</html>\n";
1336 }
1337
1338 static void enable_secondary( bool & secondary, bool track_sources, bool track_tests )
1339 {
1340 if( !secondary )
1341 {
1342 try
1343 {
1344 build_module_dependency_map( track_sources, track_tests );
1345 }
1346 catch( fs::filesystem_error const & x )
1347 {
1348 std::cout << x.what() << std::endl;
1349 }
1350
1351 secondary = true;
1352 }
1353 }
1354
1355 static void list_modules()
1356 {
1357 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1358 {
1359 std::cout << *i << "\n";
1360 }
1361 }
1362
1363 static void list_buildable()
1364 {
1365 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1366 {
1367 if( fs::exists( module_build_path( *i ) ) && fs::exists( module_source_path( *i ) ) )
1368 {
1369 std::cout << *i << "\n";
1370 }
1371 }
1372 }
1373
1374 // module_weight_report
1375
1376 struct module_weight_actions
1377 {
1378 virtual void begin() = 0;
1379 virtual void end() = 0;
1380
1381 virtual void weight_start( int weight ) = 0;
1382 virtual void weight_end( int weight ) = 0;
1383
1384 virtual void module_start( std::string const & module ) = 0;
1385 virtual void module_end( std::string const & module ) = 0;
1386
1387 virtual void module_primary_start() = 0;
1388 virtual void module_primary( std::string const & module, int weight ) = 0;
1389 virtual void module_primary_end() = 0;
1390
1391 virtual void module_secondary_start() = 0;
1392 virtual void module_secondary( std::string const & module, int weight ) = 0;
1393 virtual void module_secondary_end() = 0;
1394 };
1395
1396 static void output_module_weight_report( module_weight_actions & actions )
1397 {
1398 // gather secondary dependencies
1399
1400 struct build_secondary_deps: public module_secondary_actions
1401 {
1402 std::map< std::string, std::set< std::string > > * pm_;
1403
1404 build_secondary_deps( std::map< std::string, std::set< std::string > > * pm ): pm_( pm )
1405 {
1406 }
1407
1408 std::string module_;
1409
1410 void heading( std::string const & module )
1411 {
1412 module_ = module;
1413 }
1414
1415 void module_start( std::string const & /*module*/ )
1416 {
1417 }
1418
1419 void module_end( std::string const & /*module*/ )
1420 {
1421 }
1422
1423 void module_adds( std::string const & module )
1424 {
1425 (*pm_)[ module_ ].insert( module );
1426 }
1427 };
1428
1429 std::map< std::string, std::set< std::string > > secondary_deps;
1430
1431 build_secondary_deps bsd( &secondary_deps );
1432
1433 for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1434 {
1435 output_module_secondary_report( *i, bsd );
1436 }
1437
1438 // build weight map
1439
1440 std::map< int, std::set< std::string > > modules_by_weight;
1441
1442 for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
1443 {
1444 int w = s_module_deps[ *i ].size() + secondary_deps[ *i ].size();
1445 modules_by_weight[ w ].insert( *i );
1446 }
1447
1448 // output report
1449
1450 actions.begin();
1451
1452 for( std::map< int, std::set< std::string > >::const_iterator i = modules_by_weight.begin(); i != modules_by_weight.end(); ++i )
1453 {
1454 actions.weight_start( i->first );
1455
1456 for( std::set< std::string >::const_iterator j = i->second.begin(); j != i->second.end(); ++j )
1457 {
1458 actions.module_start( *j );
1459
1460 if( !s_module_deps[ *j ].empty() )
1461 {
1462 actions.module_primary_start();
1463
1464 for( std::set< std::string >::const_iterator k = s_module_deps[ *j ].begin(); k != s_module_deps[ *j ].end(); ++k )
1465 {
1466 int w = s_module_deps[ *k ].size() + secondary_deps[ *k ].size();
1467 actions.module_primary( *k, w );
1468 }
1469
1470 actions.module_primary_end();
1471 }
1472
1473 if( !secondary_deps[ *j ].empty() )
1474 {
1475 actions.module_secondary_start();
1476
1477 for( std::set< std::string >::const_iterator k = secondary_deps[ *j ].begin(); k != secondary_deps[ *j ].end(); ++k )
1478 {
1479 int w = s_module_deps[ *k ].size() + secondary_deps[ *k ].size();
1480 actions.module_secondary( *k, w );
1481 }
1482
1483 actions.module_secondary_end();
1484 }
1485
1486 actions.module_end( *j );
1487 }
1488
1489 actions.weight_end( i->first );
1490 }
1491
1492 actions.end();
1493 }
1494
1495 struct module_weight_txt_actions: public module_weight_actions
1496 {
1497 void begin()
1498 {
1499 std::cout << "Module Weights:\n\n";
1500 }
1501
1502 void end()
1503 {
1504 }
1505
1506 void weight_start( int weight )
1507 {
1508 std::cout << "Weight " << weight << ":\n";
1509 }
1510
1511 void weight_end( int /*weight*/ )
1512 {
1513 std::cout << "\n";
1514 }
1515
1516 void module_start( std::string const & module )
1517 {
1518 std::cout << " " << module;
1519 }
1520
1521 void module_end( std::string const & /*module*/ )
1522 {
1523 std::cout << "\n";
1524 }
1525
1526 void module_primary_start()
1527 {
1528 std::cout << " ->";
1529 }
1530
1531 void module_primary( std::string const & module, int weight )
1532 {
1533 std::cout << " " << module << "(" << weight << ")";
1534 }
1535
1536 void module_primary_end()
1537 {
1538 }
1539
1540 void module_secondary_start()
1541 {
1542 std::cout << " ->";
1543 }
1544
1545 void module_secondary( std::string const & module, int /*weight*/ )
1546 {
1547 std::cout << " " << module;
1548 }
1549
1550 void module_secondary_end()
1551 {
1552 }
1553 };
1554
1555 struct module_weight_html_actions: public module_weight_actions
1556 {
1557 int weight_;
1558
1559 void begin()
1560 {
1561 std::cout << "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
1562 }
1563
1564 void end()
1565 {
1566 std::cout << "</div>\n";
1567 }
1568
1569 void weight_start( int weight )
1570 {
1571 std::cout << " <h2 id='weight:" << weight << "'>Weight " << weight << "</h2>\n";
1572 weight_ = weight;
1573 }
1574
1575 void weight_end( int /*weight*/ )
1576 {
1577 }
1578
1579 void module_start( std::string const & module )
1580 {
1581 std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3>";
1582 }
1583
1584 void module_end( std::string const & /*module*/ )
1585 {
1586 std::cout << "\n";
1587 }
1588
1589 void module_primary_start()
1590 {
1591 std::cout << "<p class='primary-list'>";
1592 }
1593
1594 void module_primary( std::string const & module, int weight )
1595 {
1596 std::cout << " ";
1597
1598 bool heavy = weight >= 0.8 * weight_;
1599
1600 if( heavy )
1601 {
1602 std::cout << "<strong>";
1603 }
1604
1605 std::cout << module << "<sup>" << weight << "</sup>";
1606
1607 if( heavy )
1608 {
1609 std::cout << "</strong>";
1610 }
1611 }
1612
1613 void module_primary_end()
1614 {
1615 std::cout << "</p>";
1616 }
1617
1618 void module_secondary_start()
1619 {
1620 std::cout << "<p class='secondary-list'>";
1621 }
1622
1623 void module_secondary( std::string const & module, int /*weight*/ )
1624 {
1625 std::cout << " " << module;
1626 }
1627
1628 void module_secondary_end()
1629 {
1630 std::cout << "</p>";
1631 }
1632 };
1633
1634 static void output_module_weight_report( bool html )
1635 {
1636 if( html )
1637 {
1638 module_weight_html_actions actions;
1639 output_module_weight_report( actions );
1640 }
1641 else
1642 {
1643 module_weight_txt_actions actions;
1644 output_module_weight_report( actions );
1645 }
1646 }
1647
1648 // output_module_subset_report
1649
1650 struct module_subset_actions
1651 {
1652 virtual void heading( std::string const & module ) = 0;
1653
1654 virtual void module_start( std::string const & module ) = 0;
1655 virtual void module_end( std::string const & module ) = 0;
1656
1657 virtual void from_path( std::vector<std::string> const & path ) = 0;
1658 };
1659
1660 static void add_module_headers( fs::path const & dir, std::set<std::string> & headers )
1661 {
1662 if( fs::exists( dir ) )
1663 {
1664 fs::recursive_directory_iterator it( dir ), last;
1665
1666 for( ; it != last; ++it )
1667 {
1668 if( it->status().type() == fs::directory_file )
1669 {
1670 continue;
1671 }
1672
1673 headers.insert( it->path().generic_string() );
1674 }
1675 }
1676 }
1677
1678 static void output_module_subset_report_( std::string const & module, std::set<std::string> const & headers, module_subset_actions & actions )
1679 {
1680 // build header closure
1681
1682 // header -> (header)*
1683 std::map< std::string, std::set<std::string> > inc2;
1684
1685 // (header, header) -> path
1686 std::map< std::pair<std::string, std::string>, std::vector<std::string> > paths;
1687
1688 for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
1689 {
1690 std::set<std::string> & s = inc2[ *i ];
1691
1692 s = s_header_includes[ *i ];
1693
1694 for( std::set<std::string>::const_iterator j = s.begin(); j != s.end(); ++j )
1695 {
1696 std::vector<std::string> & v = paths[ std::make_pair( *i, *j ) ];
1697
1698 v.resize( 0 );
1699 v.push_back( *i );
1700 v.push_back( *j );
1701 }
1702 }
1703
1704 for( ;; )
1705 {
1706 bool r = false;
1707
1708 for( std::map< std::string, std::set<std::string> >::iterator i = inc2.begin(); i != inc2.end(); ++i )
1709 {
1710 std::set<std::string> & s2 = i->second;
1711
1712 for( std::set<std::string>::const_iterator j = s2.begin(); j != s2.end(); ++j )
1713 {
1714 std::set<std::string> const & s = s_header_includes[ *j ];
1715
1716 for( std::set<std::string>::const_iterator k = s.begin(); k != s.end(); ++k )
1717 {
1718 if( s2.count( *k ) == 0 )
1719 {
1720 s2.insert( *k );
1721
1722 std::vector<std::string> const & v1 = paths[ std::make_pair( i->first, *j ) ];
1723 std::vector<std::string> & v2 = paths[ std::make_pair( i->first, *k ) ];
1724
1725 v2 = v1;
1726 v2.push_back( *k );
1727
1728 r = true;
1729 }
1730 }
1731 }
1732 }
1733
1734 if( !r ) break;
1735 }
1736
1737 // module -> header -> path [header -> header -> header]
1738 std::map< std::string, std::map< std::string, std::vector<std::string> > > subset;
1739
1740 for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
1741 {
1742 std::set<std::string> const & s = inc2[ *i ];
1743
1744 for( std::set<std::string>::const_iterator j = s.begin(); j != s.end(); ++j )
1745 {
1746 std::string const & m = s_header_map[ *j ];
1747
1748 if( m.empty() ) continue;
1749
1750 std::vector<std::string> const & path = paths[ std::make_pair( *i, *j ) ];
1751
1752 if( subset.count( m ) == 0 || subset[ m ].count( *i ) == 0 || subset[ m ][ *i ].size() > path.size() )
1753 {
1754 subset[ m ][ *i ] = path;
1755 }
1756 }
1757 }
1758
1759 actions.heading( module );
1760
1761 for( std::map< std::string, std::map< std::string, std::vector<std::string> > >::const_iterator i = subset.begin(); i != subset.end(); ++i )
1762 {
1763 if( i->first == module ) continue;
1764
1765 actions.module_start( i->first );
1766
1767 int k = 0;
1768
1769 for( std::map< std::string, std::vector<std::string> >::const_iterator j = i->second.begin(); j != i->second.end() && k < 4; ++j, ++k )
1770 {
1771 actions.from_path( j->second );
1772 }
1773
1774 actions.module_end( i->first );
1775 }
1776 }
1777
1778 static void output_module_subset_report( std::string const & module, bool track_sources, bool track_tests, module_subset_actions & actions )
1779 {
1780 std::set<std::string> headers = s_module_headers[ module ];
1781
1782 if( track_sources )
1783 {
1784 add_module_headers( module_source_path( module ), headers );
1785 }
1786
1787 if( track_tests )
1788 {
1789 add_module_headers( module_test_path( module ), headers );
1790 }
1791
1792 output_module_subset_report_( module, headers, actions );
1793 }
1794
1795 struct module_subset_txt_actions: public module_subset_actions
1796 {
1797 void heading( std::string const & module )
1798 {
1799 std::cout << "Subset dependencies for " << module << ":\n\n";
1800 }
1801
1802 void module_start( std::string const & module )
1803 {
1804 std::cout << module << ":\n";
1805 }
1806
1807 void module_end( std::string const & /*module*/ )
1808 {
1809 std::cout << "\n";
1810 }
1811
1812 void from_path( std::vector<std::string> const & path )
1813 {
1814 for( std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i )
1815 {
1816 if( i == path.begin() )
1817 {
1818 std::cout << " ";
1819 }
1820 else
1821 {
1822 std::cout << " -> ";
1823 }
1824
1825 std::cout << *i;
1826 }
1827
1828 std::cout << "\n";
1829 }
1830 };
1831
1832 struct module_subset_html_actions: public module_subset_actions
1833 {
1834 void heading( std::string const & module )
1835 {
1836 std::cout << "\n\n<h1 id=\"subset-dependencies\">Subset dependencies for <em>" << module << "</em></h1>\n";
1837 }
1838
1839 void module_start( std::string const & module )
1840 {
1841 std::cout << " <h2 id=\"subset-" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
1842 }
1843
1844 void module_end( std::string const & /*module*/ )
1845 {
1846 std::cout << "</ul>\n";
1847 }
1848
1849 void from_path( std::vector<std::string> const & path )
1850 {
1851 std::cout << " <li>";
1852
1853 for( std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i )
1854 {
1855 if( i != path.begin() )
1856 {
1857 std::cout << " &#8674; ";
1858 }
1859
1860 std::cout << "<code>" << *i << "</code>";
1861 }
1862
1863 std::cout << "</li>\n";
1864 }
1865 };
1866
1867 static void output_module_subset_report( std::string const & module, bool track_sources, bool track_tests, bool html )
1868 {
1869 if( html )
1870 {
1871 module_subset_html_actions actions;
1872 output_module_subset_report( module, track_sources, track_tests, actions );
1873 }
1874 else
1875 {
1876 module_subset_txt_actions actions;
1877 output_module_subset_report( module, track_sources, track_tests, actions );
1878 }
1879 }
1880
1881 // --list-exceptions
1882
1883 static void list_exceptions()
1884 {
1885 std::string lm;
1886
1887 for( std::map< std::string, std::set<std::string> >::const_iterator i = s_module_headers.begin(); i != s_module_headers.end(); ++i )
1888 {
1889 std::string module = i->first;
1890
1891 std::replace( module.begin(), module.end(), '~', '/' );
1892
1893 std::string const prefix = "boost/" + module;
1894 size_t const n = prefix.size();
1895
1896 for( std::set< std::string >::const_iterator j = i->second.begin(); j != i->second.end(); ++j )
1897 {
1898 std::string const & header = *j;
1899
1900 if( header.substr( 0, n+1 ) != prefix + '/' && header != prefix + ".hpp" )
1901 {
1902 if( lm != module )
1903 {
1904 std::cout << module << ":\n";
1905 lm = module;
1906 }
1907
1908 std::cout << " " << header << '\n';
1909 }
1910 }
1911 }
1912 }
1913
1914 // --test
1915
1916 struct module_test_primary_actions: public module_primary_actions
1917 {
1918 std::set< std::string > & m_;
1919
1920 module_test_primary_actions( std::set< std::string > & m ): m_( m )
1921 {
1922 }
1923
1924 void heading( std::string const & module )
1925 {
1926 std::cout << "Test dependencies for " << module << ":\n\n";
1927 }
1928
1929 void module_start( std::string const & module )
1930 {
1931 std::cout << module << "\n";
1932 m_.insert( module );
1933 }
1934
1935 void module_end( std::string const & /*module*/ )
1936 {
1937 }
1938
1939 void header_start( std::string const & /*header*/ )
1940 {
1941 }
1942
1943 void header_end( std::string const & /*header*/ )
1944 {
1945 }
1946
1947 void from_header( std::string const & /*header*/ )
1948 {
1949 }
1950 };
1951
1952 struct module_test_secondary_actions: public module_secondary_actions
1953 {
1954 std::set< std::string > & m_;
1955 std::string m2_;
1956
1957 module_test_secondary_actions( std::set< std::string > & m ): m_( m )
1958 {
1959 }
1960
1961 void heading( std::string const & /*module*/ )
1962 {
1963 }
1964
1965 void module_start( std::string const & module )
1966 {
1967 m2_ = module;
1968 }
1969
1970 void module_end( std::string const & /*module*/ )
1971 {
1972 }
1973
1974 void module_adds( std::string const & module )
1975 {
1976 if( m_.count( module ) == 0 )
1977 {
1978 std::cout << module << " (from " << m2_ << ")\n";
1979 m_.insert( module );
1980 }
1981 }
1982 };
1983
1984 static void output_module_test_report( std::string const & module )
1985 {
1986 std::set< std::string > m;
1987
1988 module_test_primary_actions a1( m );
1989 output_module_primary_report( module, a1, true, true );
1990
1991 std::cout << "\n";
1992
1993 bool secondary = false;
1994 enable_secondary( secondary, true, false );
1995
1996 std::set< std::string > m2( m );
1997 m2.insert( module );
1998
1999 module_test_secondary_actions a2( m2 );
2000
2001 output_module_secondary_report( module, m, a2 );
2002 }
2003
2004 // --cmake
2005
2006 struct collect_primary_dependencies: public module_primary_actions
2007 {
2008 std::set< std::string > set_;
2009
2010 void heading( std::string const & )
2011 {
2012 }
2013
2014 void module_start( std::string const & module )
2015 {
2016 if( module == "(unknown)" ) return;
2017
2018 set_.insert( module );
2019 }
2020
2021 void module_end( std::string const & /*module*/ )
2022 {
2023 }
2024
2025 void header_start( std::string const & /*header*/ )
2026 {
2027 }
2028
2029 void header_end( std::string const & /*header*/ )
2030 {
2031 }
2032
2033 void from_header( std::string const & /*header*/ )
2034 {
2035 }
2036 };
2037
2038 static std::string module_cmake_package( std::string module )
2039 {
2040 std::replace( module.begin(), module.end(), '~', '_' );
2041 return "boost_" + module;
2042 }
2043
2044 static std::string module_cmake_target( std::string module )
2045 {
2046 std::replace( module.begin(), module.end(), '~', '_' );
2047 return "boost::" + module;
2048 }
2049
2050 static void output_module_cmake_report( std::string module )
2051 {
2052 std::replace( module.begin(), module.end(), '/', '~' );
2053
2054 std::cout << "# Generated file. Do not edit.\n\n";
2055
2056 collect_primary_dependencies a1;
2057 output_module_primary_report( module, a1, false, false );
2058
2059 if( !fs::exists( module_source_path( module ) ) )
2060 {
2061 for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
2062 {
2063 std::cout << "boost_declare_dependency(" << module_cmake_package( *i ) << " INTERFACE " << module_cmake_target( *i ) << ")\n";
2064 }
2065 }
2066 else
2067 {
2068 collect_primary_dependencies a2;
2069 output_module_primary_report( module, a2, true, false );
2070
2071 for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
2072 {
2073 a2.set_.erase( *i );
2074 std::cout << "boost_declare_dependency(" << module_cmake_package( *i ) << " PUBLIC " << module_cmake_target( *i ) << ")\n";
2075 }
2076
2077 std::cout << "\n";
2078
2079 for( std::set< std::string >::const_iterator i = a2.set_.begin(); i != a2.set_.end(); ++i )
2080 {
2081 std::cout << "boost_declare_dependency(" << module_cmake_package( *i ) << " PRIVATE " << module_cmake_target( *i ) << ")\n";
2082 }
2083 }
2084 }
2085
2086 // --list-missing-headers
2087
2088 struct missing_header_actions: public module_primary_actions
2089 {
2090 std::string module_, module2_;
2091
2092 void heading( std::string const & module )
2093 {
2094 module_ = module;
2095 }
2096
2097 void module_start( std::string const & module )
2098 {
2099 module2_ = module;
2100 }
2101
2102 void module_end( std::string const & /*module*/ )
2103 {
2104 }
2105
2106 void header_start( std::string const & header )
2107 {
2108 if( module2_ == "(unknown)" )
2109 {
2110 if( !module_.empty() )
2111 {
2112 std::cout << module_ << ":\n";
2113 module_.clear();
2114 }
2115
2116 std::cout << " <" << header << ">\n";
2117 }
2118 }
2119
2120 void header_end( std::string const & /*header*/ )
2121 {
2122 }
2123
2124 void from_header( std::string const & header )
2125 {
2126 if( module2_ == "(unknown)" )
2127 {
2128 std::cout << " from <" << header << ">\n";
2129 }
2130 }
2131 };
2132
2133 static void list_missing_headers( std::string const & module )
2134 {
2135 missing_header_actions a;
2136 output_module_primary_report( module, a, false, false );
2137 }
2138
2139 static void list_missing_headers()
2140 {
2141 for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
2142 {
2143 list_missing_headers( *i );
2144 }
2145 }
2146
2147 // --pkgconfig
2148
2149 struct primary_pkgconfig_actions: public module_primary_actions
2150 {
2151 std::string version_;
2152 std::string list_;
2153
2154 void heading( std::string const & )
2155 {
2156 }
2157
2158 void module_start( std::string const & module )
2159 {
2160 if( module == "(unknown)" ) return;
2161
2162 std::string m2( module );
2163 std::replace( m2.begin(), m2.end(), '~', '_' );
2164
2165 if( !list_.empty() )
2166 {
2167 list_ += ", ";
2168 }
2169
2170 list_ += "boost_" + m2 + " = " + version_;
2171 }
2172
2173 void module_end( std::string const & )
2174 {
2175 }
2176
2177 void header_start( std::string const & )
2178 {
2179 }
2180
2181 void header_end( std::string const & )
2182 {
2183 }
2184
2185 void from_header( std::string const & )
2186 {
2187 }
2188 };
2189
2190 static void output_requires( std::string const & section, std::string const & version, std::set< std::string > const & s )
2191 {
2192 bool first = true;
2193
2194 for( std::set< std::string >::const_iterator i = s.begin(); i != s.end(); ++i )
2195 {
2196 if( first )
2197 {
2198 std::cout << section << ": ";
2199 first = false;
2200 }
2201 else
2202 {
2203 std::cout << ", ";
2204 }
2205
2206 std::string m2( *i );
2207 std::replace( m2.begin(), m2.end(), '~', '_' );
2208
2209 std::cout << "boost_" << m2 << " = " << version;
2210 }
2211 }
2212
2213 static void output_pkgconfig( std::string const & module, std::string const & version, int argc, char const* argv[] )
2214 {
2215 for( int i = 0; i < argc; ++i )
2216 {
2217 std::cout << argv[ i ] << '\n';
2218 }
2219
2220 std::cout << '\n';
2221
2222 std::string m2( module );
2223 std::replace( m2.begin(), m2.end(), '/', '_' );
2224
2225 std::string m3( module );
2226 std::replace( m3.begin(), m3.end(), '/', '~' );
2227
2228 std::cout << "Name: boost_" << module << '\n';
2229 std::cout << "Description: Boost C++ library '" << module << "'\n";
2230 std::cout << "Version: " << version << '\n';
2231 std::cout << "URL: http://www.boost.org/libs/" << module << '\n';
2232 std::cout << "Cflags: -I${includedir}\n";
2233
2234 if( fs::exists( module_build_path( module ) ) && fs::exists( module_source_path( module ) ) )
2235 {
2236 std::cout << "Libs: -L${libdir} -lboost_" << m2 << "\n";
2237 }
2238
2239 collect_primary_dependencies a1;
2240 output_module_primary_report( m3, a1, false, false );
2241
2242 if( !a1.set_.empty() )
2243 {
2244 output_requires( "Requires", version, a1.set_ );
2245 std::cout << std::endl;
2246 }
2247
2248 collect_primary_dependencies a2;
2249 output_module_primary_report( m3, a2, true, false );
2250
2251 for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
2252 {
2253 a2.set_.erase( *i );
2254 }
2255
2256 if( !a2.set_.empty() )
2257 {
2258 output_requires( "Requires.private", version, a2.set_ );
2259 std::cout << std::endl;
2260 }
2261 }
2262
2263 // --subset-for
2264
2265 static void output_directory_subset_report( std::string const & module, std::set<std::string> const & headers, bool html )
2266 {
2267 for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
2268 {
2269 std::map< std::string, std::set< std::string > > deps;
2270 std::map< std::string, std::set< std::string > > from;
2271
2272 std::ifstream is( i->c_str() );
2273 scan_header_dependencies( *i, is, deps, from );
2274
2275 for( std::map< std::string, std::set< std::string > >::const_iterator j = from.begin(); j != from.end(); ++j )
2276 {
2277 for( std::set<std::string>::const_iterator k = j->second.begin(); k != j->second.end(); ++k )
2278 {
2279 s_header_includes[ *k ].insert( j->first );
2280 }
2281 }
2282 }
2283
2284 if( html )
2285 {
2286 module_subset_html_actions actions;
2287 output_module_subset_report_( module, headers, actions );
2288 }
2289 else
2290 {
2291 module_subset_txt_actions actions;
2292 output_module_subset_report_( module, headers, actions );
2293 }
2294 }
2295
2296 //
2297
2298 static bool find_boost_root()
2299 {
2300 for( int i = 0; i < 32; ++i )
2301 {
2302 if( fs::exists( "Jamroot" ) )
2303 {
2304 return true;
2305 }
2306
2307 fs::path p = fs::current_path();
2308
2309 if( p == p.root_path() )
2310 {
2311 return false;
2312 }
2313
2314 fs::current_path( p.parent_path() );
2315 }
2316
2317 return false;
2318 }
2319
2320 int main( int argc, char const* argv[] )
2321 {
2322 if( argc < 2 )
2323 {
2324 std::cout <<
2325
2326 "Usage:\n"
2327 "\n"
2328 " boostdep --list-modules\n"
2329 " boostdep --list-buildable\n"
2330 " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
2331 " boostdep --list-exceptions\n"
2332 " boostdep --list-missing-headers\n"
2333 "\n"
2334 " boostdep [options] --module-overview\n"
2335 " boostdep [options] --module-levels\n"
2336 " boostdep [options] --module-weights\n"
2337 "\n"
2338 " boostdep [options] [--primary] <module>\n"
2339 " boostdep [options] --secondary <module>\n"
2340 " boostdep [options] --reverse <module>\n"
2341 " boostdep [options] --subset <module>\n"
2342 " boostdep [options] [--header] <header>\n"
2343 " boostdep --test <module>\n"
2344 " boostdep --cmake <module>\n"
2345 " boostdep --pkgconfig <module> <version> [<var>=<value>] [<var>=<value>]...\n"
2346 " boostdep [options] --subset-for <directory>\n"
2347 "\n"
2348 " [options]: [--[no-]track-sources] [--[no-]track-tests]\n"
2349 " [--html-title <title>] [--html-footer <footer>]\n"
2350 " [--html-stylesheet <stylesheet>] [--html-prefix <prefix>]\n"
2351 " [--html]\n";
2352
2353 return -1;
2354 }
2355
2356 if( !find_boost_root() )
2357 {
2358 std::cerr << "boostdep: Could not find Boost root.\n";
2359 return -2;
2360 }
2361
2362 try
2363 {
2364 build_header_map();
2365 }
2366 catch( fs::filesystem_error const & x )
2367 {
2368 std::cout << x.what() << std::endl;
2369 }
2370
2371 bool html = false;
2372 bool secondary = false;
2373 bool track_sources = false;
2374 bool track_tests = false;
2375
2376 std::string html_title = "Boost Dependency Report";
2377 std::string html_footer;
2378 std::string html_stylesheet;
2379 std::string html_prefix;
2380
2381 for( int i = 1; i < argc; ++i )
2382 {
2383 std::string option = argv[ i ];
2384
2385 if( option == "--list-modules" )
2386 {
2387 list_modules();
2388 }
2389 else if( option == "--list-buildable" )
2390 {
2391 list_buildable();
2392 }
2393 else if( option == "--title" || option == "--html-title" )
2394 {
2395 if( i + 1 < argc )
2396 {
2397 html_title = argv[ ++i ];
2398 }
2399 }
2400 else if( option == "--footer" || option == "--html-footer" )
2401 {
2402 if( i + 1 < argc )
2403 {
2404 html_footer = argv[ ++i ];
2405 }
2406 }
2407 else if( option == "--html-stylesheet" )
2408 {
2409 if( i + 1 < argc )
2410 {
2411 html_stylesheet = argv[ ++i ];
2412 }
2413 }
2414 else if( option == "--html-prefix" )
2415 {
2416 if( i + 1 < argc )
2417 {
2418 html_prefix = argv[ ++i ];
2419 }
2420 }
2421 else if( option == "--html" )
2422 {
2423 if( !html )
2424 {
2425 html = true;
2426 output_html_header( html_title, html_stylesheet, html_prefix );
2427 }
2428 }
2429 else if( option == "--track-sources" )
2430 {
2431 track_sources = true;
2432 }
2433 else if( option == "--no-track-sources" )
2434 {
2435 track_sources = false;
2436 }
2437 else if( option == "--track-tests" )
2438 {
2439 track_tests = true;
2440 }
2441 else if( option == "--no-track-tests" )
2442 {
2443 track_tests = false;
2444 }
2445 else if( option == "--primary" )
2446 {
2447 if( i + 1 < argc )
2448 {
2449 output_module_primary_report( argv[ ++i ], html, track_sources, track_tests );
2450 }
2451 }
2452 else if( option == "--secondary" )
2453 {
2454 if( i + 1 < argc )
2455 {
2456 enable_secondary( secondary, track_sources, track_tests );
2457 output_module_secondary_report( argv[ ++i ], html );
2458 }
2459 }
2460 else if( option == "--reverse" )
2461 {
2462 if( i + 1 < argc )
2463 {
2464 enable_secondary( secondary, track_sources, track_tests );
2465 output_module_reverse_report( argv[ ++i ], html );
2466 }
2467 }
2468 else if( option == "--header" )
2469 {
2470 if( i + 1 < argc )
2471 {
2472 enable_secondary( secondary, track_sources, track_tests );
2473 output_header_report( argv[ ++i ], html );
2474 }
2475 }
2476 else if( option == "--subset" )
2477 {
2478 if( i + 1 < argc )
2479 {
2480 enable_secondary( secondary, track_sources, track_tests );
2481 output_module_subset_report( argv[ ++i ], track_sources, track_tests, html );
2482 }
2483 }
2484 else if( option == "--test" )
2485 {
2486 if( i + 1 < argc )
2487 {
2488 output_module_test_report( argv[ ++i ] );
2489 }
2490 }
2491 else if( option == "--cmake" )
2492 {
2493 if( i + 1 < argc )
2494 {
2495 output_module_cmake_report( argv[ ++i ] );
2496 }
2497 }
2498 else if( option == "--module-levels" )
2499 {
2500 enable_secondary( secondary, track_sources, track_tests );
2501 output_module_level_report( html );
2502 }
2503 else if( option == "--module-overview" )
2504 {
2505 enable_secondary( secondary, track_sources, track_tests );
2506 output_module_overview_report( html );
2507 }
2508 else if( option == "--module-weights" )
2509 {
2510 enable_secondary( secondary, track_sources, track_tests );
2511 output_module_weight_report( html );
2512 }
2513 else if( option == "--list-dependencies" )
2514 {
2515 enable_secondary( secondary, track_sources, track_tests );
2516 list_dependencies();
2517 }
2518 else if( option == "--list-exceptions" )
2519 {
2520 list_exceptions();
2521 }
2522 else if( option == "--list-missing-headers" )
2523 {
2524 list_missing_headers();
2525 }
2526 else if( option == "--pkgconfig" )
2527 {
2528 if( i + 2 < argc )
2529 {
2530 std::string module = argv[ ++i ];
2531 std::string version = argv[ ++i ];
2532
2533 ++i;
2534
2535 output_pkgconfig( module, version, argc - i, argv + i );
2536 }
2537 else
2538 {
2539 std::cerr << "'" << option << "': missing module or version.\n";
2540 }
2541
2542 break;
2543 }
2544 else if( option == "--subset-for" )
2545 {
2546 if( i + 1 < argc )
2547 {
2548 std::string module = argv[ ++i ];
2549
2550 enable_secondary( secondary, track_sources, track_tests );
2551
2552 std::set<std::string> headers;
2553 add_module_headers( module, headers );
2554
2555 output_directory_subset_report( module, headers, html );
2556 }
2557 else
2558 {
2559 std::cerr << "'" << option << "': missing argument.\n";
2560 }
2561
2562 break;
2563 }
2564 else if( s_modules.count( option ) )
2565 {
2566 output_module_primary_report( option, html, track_sources, track_tests );
2567 }
2568 else if( s_header_map.count( option ) )
2569 {
2570 enable_secondary( secondary, track_sources, track_tests );
2571 output_header_report( option, html );
2572 }
2573 else
2574 {
2575 std::cerr << "'" << option << "': not an option, module or header.\n";
2576 }
2577 }
2578
2579 if( html )
2580 {
2581 output_html_footer( html_footer );
2582 }
2583 }