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