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