]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/boostdep/src/boostdep.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / boostdep / src / boostdep.cpp
CommitLineData
7c673cae
FG
1
2// boostdep - a tool to generate Boost dependency reports
3//
b32b8144 4// Copyright 2014-2017 Peter Dimov
7c673cae
FG
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
22namespace fs = boost::filesystem;
23
24// header -> module
25static std::map< std::string, std::string > s_header_map;
26
27// module -> headers
28static std::map< std::string, std::set<std::string> > s_module_headers;
29
30static std::set< std::string > s_modules;
31
32static 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 {
b32b8144
FG
49 if( it->status().type() == fs::directory_file )
50 {
51 continue;
52 }
7c673cae 53
b32b8144 54 std::string p2 = it->path().generic_string();
7c673cae
FG
55 p2 = p2.substr( n+1 );
56
7c673cae
FG
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
67static 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
94static void build_header_map()
95{
96 scan_submodules( "libs" );
97}
98
99static 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
163struct 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
176static 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
182static 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
188static 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
b32b8144 194static fs::path module_test_path( std::string module )
7c673cae 195{
b32b8144
FG
196 std::replace( module.begin(), module.end(), '~', '/' );
197 return fs::path( "libs" ) / module / "test";
198}
7c673cae 199
b32b8144
FG
200static 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();
7c673cae 203
b32b8144 204 if( fs::exists( dir ) )
7c673cae 205 {
7c673cae
FG
206 fs::recursive_directory_iterator it( dir ), last;
207
208 for( ; it != last; ++it )
209 {
b32b8144
FG
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 }
7c673cae
FG
221
222 fs::ifstream is( it->path() );
223
224 scan_header_dependencies( header, is, deps, from );
225 }
226 }
b32b8144 227}
7c673cae 228
b32b8144
FG
229static 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;
7c673cae 233
b32b8144
FG
234 // header -> included from [ header, header... ]
235 std::map< std::string, std::set< std::string > > from;
7c673cae 236
b32b8144 237 scan_module_path( module_include_path( module ), true, deps, from );
7c673cae 238
b32b8144
FG
239 if( track_sources )
240 {
241 scan_module_path( module_source_path( module ), false, deps, from );
242 }
7c673cae 243
b32b8144
FG
244 if( track_tests )
245 {
246 scan_module_path( module_test_path( module ), false, deps, from );
7c673cae
FG
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... ]
276static std::map< std::string, std::set< std::string > > s_module_deps;
277
278// header is included by [header, header...]
279static std::map< std::string, std::set< std::string > > s_header_deps;
280
281// [ module, module... ] depend on module
282static std::map< std::string, std::set< std::string > > s_reverse_deps;
283
284// header includes [header, header...]
285static std::map< std::string, std::set< std::string > > s_header_includes;
286
287struct 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
b32b8144 333static void build_module_dependency_map( bool track_sources, bool track_tests )
7c673cae
FG
334{
335 for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
336 {
337 build_mdmap_actions actions;
b32b8144 338 scan_module_dependencies( *i, actions, track_sources, track_tests, true );
7c673cae
FG
339 }
340}
341
b32b8144 342static void output_module_primary_report( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests )
7c673cae
FG
343{
344 try
345 {
b32b8144 346 scan_module_dependencies( module, actions, track_sources, track_tests, false );
7c673cae
FG
347 }
348 catch( fs::filesystem_error const & x )
349 {
350 std::cout << x.what() << std::endl;
351 }
352}
353
354struct 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
364static 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
b32b8144 372static void output_module_secondary_report( std::string const & module, std::set< std::string> deps, module_secondary_actions & actions )
7c673cae
FG
373{
374 actions.heading( module );
375
7c673cae
FG
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
b32b8144
FG
418static 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
7c673cae
FG
423struct 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
433static 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
466struct 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
498struct 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
b32b8144 530static void output_module_primary_report( std::string const & module, bool html, bool track_sources, bool track_tests )
7c673cae
FG
531{
532 if( html )
533 {
534 module_primary_html_actions actions;
b32b8144 535 output_module_primary_report( module, actions, track_sources, track_tests );
7c673cae
FG
536 }
537 else
538 {
539 module_primary_txt_actions actions;
b32b8144 540 output_module_primary_report( module, actions, track_sources, track_tests );
7c673cae
FG
541 }
542}
543
544// output_module_secondary_report
545
546struct 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
569struct 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
595static 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
611struct 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
634struct 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
657static 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
673struct 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
686static 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
728struct 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
760struct 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
792static 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
808int const unknown_level = INT_MAX / 2;
809
810struct module_level_actions
811{
b32b8144
FG
812 virtual void begin() = 0;
813 virtual void end() = 0;
7c673cae
FG
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
824static 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
b32b8144 976 actions.begin();
7c673cae
FG
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 }
b32b8144
FG
1010
1011 actions.end();
7c673cae
FG
1012}
1013
1014struct module_level_txt_actions: public module_level_actions
1015{
1016 int level_;
1017
b32b8144 1018 void begin()
7c673cae
FG
1019 {
1020 std::cout << "Module Levels:\n\n";
1021 }
1022
b32b8144
FG
1023 void end()
1024 {
1025 }
1026
7c673cae
FG
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
1078struct module_level_html_actions: public module_level_actions
1079{
1080 int level_;
1081
b32b8144 1082 void begin()
7c673cae 1083 {
b32b8144 1084 std::cout << "<div id='module-levels'><h1>Module Levels</h1>\n";
7c673cae
FG
1085 }
1086
b32b8144 1087 void end()
7c673cae 1088 {
b32b8144
FG
1089 std::cout << "</div>\n";
1090 }
7c673cae 1091
b32b8144
FG
1092 void level_start( int level )
1093 {
7c673cae
FG
1094 if( level >= unknown_level )
1095 {
b32b8144 1096 std::cout << " <h2>Level <em>undetermined</em></h2>\n";
7c673cae
FG
1097 }
1098 else
1099 {
b32b8144 1100 std::cout << " <h2 id='level:" << level << "'>Level " << level << "</h2>\n";
7c673cae
FG
1101 }
1102
7c673cae
FG
1103 level_ = level;
1104 }
1105
1106 void level_end( int /*level*/ )
1107 {
7c673cae
FG
1108 }
1109
1110 void module_start( std::string const & module )
1111 {
b32b8144 1112 std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3><p class='primary-list'>";
7c673cae
FG
1113 }
1114
1115 void module_end( std::string const & /*module*/ )
1116 {
b32b8144 1117 std::cout << "</p>\n";
7c673cae
FG
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
1145static 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
1161struct module_overview_actions
1162{
b32b8144
FG
1163 virtual void begin() = 0;
1164 virtual void end() = 0;
7c673cae
FG
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
1172static void output_module_overview_report( module_overview_actions & actions )
1173{
b32b8144 1174 actions.begin();
7c673cae
FG
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 }
b32b8144
FG
1189
1190 actions.end();
7c673cae
FG
1191}
1192
1193struct module_overview_txt_actions: public module_overview_actions
1194{
1195 bool deps_;
1196
b32b8144 1197 void begin()
7c673cae
FG
1198 {
1199 std::cout << "Module Overview:\n\n";
1200 }
1201
b32b8144
FG
1202 void end()
1203 {
1204 }
1205
7c673cae
FG
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
1229struct module_overview_html_actions: public module_overview_actions
1230{
b32b8144
FG
1231 void begin()
1232 {
1233 std::cout << "<div id='module-overview'><h1>Module Overview</h1>\n";
1234 }
7c673cae 1235
b32b8144 1236 void end()
7c673cae 1237 {
b32b8144 1238 std::cout << "</div>\n";
7c673cae
FG
1239 }
1240
1241 void module_start( std::string const & module )
1242 {
b32b8144 1243 std::cout << " <h2 id='" << module << "'><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><p class='primary-list'>";
7c673cae
FG
1244 }
1245
1246 void module_end( std::string const & /*module*/ )
1247 {
b32b8144 1248 std::cout << "</p>\n";
7c673cae
FG
1249 }
1250
1251 void module2( std::string const & module )
1252 {
7c673cae
FG
1253 std::cout << " " << module;
1254 }
1255};
1256
1257static 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
1273struct list_dependencies_actions: public module_overview_actions
1274{
b32b8144
FG
1275 void begin()
1276 {
1277 }
1278
1279 void end()
7c673cae
FG
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
1302static void list_dependencies()
1303{
1304 list_dependencies_actions actions;
1305 output_module_overview_report( actions );
1306}
1307
1308//
1309
b32b8144 1310static void output_html_header( std::string const & title, std::string const & stylesheet, std::string const & prefix )
7c673cae
FG
1311{
1312 std::cout << "<html>\n";
1313 std::cout << "<head>\n";
1314 std::cout << "<title>" << title << "</title>\n";
b32b8144
FG
1315
1316 if( !stylesheet.empty() )
1317 {
1318 std::cout << "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet << "\" />\n";
1319 }
1320
7c673cae
FG
1321 std::cout << "</head>\n";
1322 std::cout << "<body>\n";
b32b8144
FG
1323
1324 if( !prefix.empty() )
1325 {
1326 std::cout << prefix << std::endl;
1327 }
7c673cae
FG
1328}
1329
1330static void output_html_footer( std::string const & footer )
1331{
1332 std::cout << "<hr />\n";
b32b8144 1333 std::cout << "<p class=\"footer\">" << footer << "</p>\n";
7c673cae
FG
1334 std::cout << "</body>\n";
1335 std::cout << "</html>\n";
1336}
1337
b32b8144 1338static void enable_secondary( bool & secondary, bool track_sources, bool track_tests )
7c673cae
FG
1339{
1340 if( !secondary )
1341 {
1342 try
1343 {
b32b8144 1344 build_module_dependency_map( track_sources, track_tests );
7c673cae
FG
1345 }
1346 catch( fs::filesystem_error const & x )
1347 {
1348 std::cout << x.what() << std::endl;
1349 }
1350
1351 secondary = true;
1352 }
1353}
1354
1355static 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
1363static 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
1376struct module_weight_actions
1377{
b32b8144
FG
1378 virtual void begin() = 0;
1379 virtual void end() = 0;
7c673cae
FG
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
1396static 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
b32b8144 1450 actions.begin();
7c673cae
FG
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 }
b32b8144
FG
1491
1492 actions.end();
7c673cae
FG
1493}
1494
1495struct module_weight_txt_actions: public module_weight_actions
1496{
b32b8144 1497 void begin()
7c673cae
FG
1498 {
1499 std::cout << "Module Weights:\n\n";
1500 }
1501
b32b8144
FG
1502 void end()
1503 {
1504 }
1505
7c673cae
FG
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
1555struct module_weight_html_actions: public module_weight_actions
1556{
1557 int weight_;
1558
b32b8144 1559 void begin()
7c673cae 1560 {
b32b8144
FG
1561 std::cout << "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
1562 }
1563
1564 void end()
1565 {
1566 std::cout << "</div>\n";
7c673cae
FG
1567 }
1568
1569 void weight_start( int weight )
1570 {
b32b8144 1571 std::cout << " <h2 id='weight:" << weight << "'>Weight " << weight << "</h2>\n";
7c673cae
FG
1572 weight_ = weight;
1573 }
1574
1575 void weight_end( int /*weight*/ )
1576 {
7c673cae
FG
1577 }
1578
1579 void module_start( std::string const & module )
1580 {
b32b8144 1581 std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3>";
7c673cae
FG
1582 }
1583
1584 void module_end( std::string const & /*module*/ )
1585 {
b32b8144 1586 std::cout << "\n";
7c673cae
FG
1587 }
1588
1589 void module_primary_start()
1590 {
b32b8144 1591 std::cout << "<p class='primary-list'>";
7c673cae
FG
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 {
b32b8144 1615 std::cout << "</p>";
7c673cae
FG
1616 }
1617
1618 void module_secondary_start()
1619 {
b32b8144 1620 std::cout << "<p class='secondary-list'>";
7c673cae
FG
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 {
b32b8144 1630 std::cout << "</p>";
7c673cae
FG
1631 }
1632};
1633
1634static 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
1650struct 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
b32b8144 1660static void add_module_headers( fs::path const & dir, std::set<std::string> & headers )
7c673cae 1661{
b32b8144
FG
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}
7c673cae 1677
b32b8144
FG
1678static void output_module_subset_report_( std::string const & module, std::set<std::string> const & headers, module_subset_actions & actions )
1679{
1680 // build header closure
7c673cae
FG
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
b32b8144
FG
1778static 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
7c673cae
FG
1795struct 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
1832struct 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
b32b8144
FG
1867static 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
1883static 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
1916struct 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
1952struct 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
1984static 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
2006struct 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
2038static std::string module_cmake_package( std::string module )
2039{
2040 std::replace( module.begin(), module.end(), '~', '_' );
2041 return "boost_" + module;
2042}
2043
2044static std::string module_cmake_target( std::string module )
2045{
2046 std::replace( module.begin(), module.end(), '~', '_' );
2047 return "boost::" + module;
2048}
2049
2050static 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
2088struct 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
2133static 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
2139static 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
2149struct 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
2190static 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
2213static void output_pkgconfig( std::string const & module, std::string const & version, int argc, char const* argv[] )
7c673cae 2214{
b32b8144
FG
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
2265static 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
7c673cae
FG
2284 if( html )
2285 {
2286 module_subset_html_actions actions;
b32b8144 2287 output_module_subset_report_( module, headers, actions );
7c673cae
FG
2288 }
2289 else
2290 {
2291 module_subset_txt_actions actions;
b32b8144
FG
2292 output_module_subset_report_( module, headers, actions );
2293 }
2294}
2295
2296//
2297
2298static 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() );
7c673cae 2315 }
b32b8144
FG
2316
2317 return false;
7c673cae
FG
2318}
2319
2320int 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"
b32b8144
FG
2330 " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
2331 " boostdep --list-exceptions\n"
2332 " boostdep --list-missing-headers\n"
7c673cae
FG
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"
b32b8144
FG
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"
7c673cae 2347 "\n"
b32b8144
FG
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";
7c673cae
FG
2352
2353 return -1;
2354 }
2355
b32b8144
FG
2356 if( !find_boost_root() )
2357 {
2358 std::cerr << "boostdep: Could not find Boost root.\n";
2359 return -2;
2360 }
2361
7c673cae
FG
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;
b32b8144 2374 bool track_tests = false;
7c673cae 2375
b32b8144
FG
2376 std::string html_title = "Boost Dependency Report";
2377 std::string html_footer;
2378 std::string html_stylesheet;
2379 std::string html_prefix;
7c673cae
FG
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 }
b32b8144
FG
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" )
7c673cae
FG
2401 {
2402 if( i + 1 < argc )
2403 {
b32b8144 2404 html_footer = argv[ ++i ];
7c673cae
FG
2405 }
2406 }
b32b8144 2407 else if( option == "--html-stylesheet" )
7c673cae
FG
2408 {
2409 if( i + 1 < argc )
2410 {
b32b8144
FG
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 ];
7c673cae
FG
2419 }
2420 }
2421 else if( option == "--html" )
2422 {
2423 if( !html )
2424 {
2425 html = true;
b32b8144 2426 output_html_header( html_title, html_stylesheet, html_prefix );
7c673cae
FG
2427 }
2428 }
2429 else if( option == "--track-sources" )
2430 {
2431 track_sources = true;
2432 }
b32b8144
FG
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 }
7c673cae
FG
2445 else if( option == "--primary" )
2446 {
2447 if( i + 1 < argc )
2448 {
b32b8144 2449 output_module_primary_report( argv[ ++i ], html, track_sources, track_tests );
7c673cae
FG
2450 }
2451 }
2452 else if( option == "--secondary" )
2453 {
2454 if( i + 1 < argc )
2455 {
b32b8144 2456 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2457 output_module_secondary_report( argv[ ++i ], html );
2458 }
2459 }
2460 else if( option == "--reverse" )
2461 {
2462 if( i + 1 < argc )
2463 {
b32b8144 2464 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2465 output_module_reverse_report( argv[ ++i ], html );
2466 }
2467 }
2468 else if( option == "--header" )
2469 {
2470 if( i + 1 < argc )
2471 {
b32b8144 2472 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2473 output_header_report( argv[ ++i ], html );
2474 }
2475 }
2476 else if( option == "--subset" )
2477 {
2478 if( i + 1 < argc )
2479 {
b32b8144
FG
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 ] );
7c673cae
FG
2496 }
2497 }
2498 else if( option == "--module-levels" )
2499 {
b32b8144 2500 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2501 output_module_level_report( html );
2502 }
2503 else if( option == "--module-overview" )
2504 {
b32b8144 2505 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2506 output_module_overview_report( html );
2507 }
2508 else if( option == "--module-weights" )
2509 {
b32b8144 2510 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2511 output_module_weight_report( html );
2512 }
2513 else if( option == "--list-dependencies" )
2514 {
b32b8144 2515 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
2516 list_dependencies();
2517 }
b32b8144
FG
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 }
7c673cae
FG
2564 else if( s_modules.count( option ) )
2565 {
b32b8144 2566 output_module_primary_report( option, html, track_sources, track_tests );
7c673cae
FG
2567 }
2568 else if( s_header_map.count( option ) )
2569 {
b32b8144 2570 enable_secondary( secondary, track_sources, track_tests );
7c673cae
FG
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 {
b32b8144 2581 output_html_footer( html_footer );
7c673cae
FG
2582 }
2583}