2 // boostdep - a tool to generate Boost dependency reports
4 // Copyright 2014-2017 Peter Dimov
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
10 #define _CRT_SECURE_NO_WARNINGS
12 #include <boost/filesystem.hpp>
13 #include <boost/filesystem/fstream.hpp>
26 namespace fs
= boost::filesystem
;
29 static std::map
< std::string
, std::string
> s_header_map
;
32 static std::map
< std::string
, std::set
<std::string
> > s_module_headers
;
34 static std::set
< std::string
> s_modules
;
36 static void scan_module_headers( fs::path
const & path
)
40 std::string module
= path
.generic_string().substr( 5 ); // strip "libs/"
42 std::replace( module
.begin(), module
.end(), '/', '~' );
44 s_modules
.insert( module
);
46 fs::path dir
= path
/ "include";
47 size_t n
= dir
.generic_string().size();
49 fs::recursive_directory_iterator
it( dir
), last
;
51 for( ; it
!= last
; ++it
)
53 if( it
->status().type() == fs::directory_file
)
58 std::string p2
= it
->path().generic_string();
59 p2
= p2
.substr( n
+1 );
61 s_header_map
[ p2
] = module
;
62 s_module_headers
[ module
].insert( p2
);
65 catch( fs::filesystem_error
const & x
)
67 std::cout
<< x
.what() << std::endl
;
71 static void scan_submodules( fs::path
const & path
)
73 fs::directory_iterator
it( path
), last
;
75 for( ; it
!= last
; ++it
)
77 fs::directory_entry
const & e
= *it
;
79 if( e
.status().type() != fs::directory_file
)
84 fs::path path
= e
.path();
86 if( fs::exists( path
/ "include" ) )
88 scan_module_headers( path
);
91 if( fs::exists( path
/ "sublibs" ) )
93 scan_submodules( path
);
98 static void build_header_map()
100 scan_submodules( "libs" );
103 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
)
107 while( std::getline( is
, line
) )
109 while( !line
.empty() && ( line
[0] == ' ' || line
[0] == '\t' ) )
114 if( line
.empty() || line
[0] != '#' ) continue;
118 while( !line
.empty() && ( line
[0] == ' ' || line
[0] == '\t' ) )
123 if( line
.substr( 0, 7 ) != "include" ) continue;
127 while( !line
.empty() && ( line
[0] == ' ' || line
[0] == '\t' ) )
132 if( line
.size() < 2 ) continue;
136 if( ch
!= '<' && ch
!= '"' ) continue;
145 std::string::size_type k
= line
.find_first_of( ch
);
147 if( k
!= std::string::npos
)
152 std::map
< std::string
, std::string
>::const_iterator i
= s_header_map
.find( line
);
154 if( i
!= s_header_map
.end() )
156 deps
[ i
->second
].insert( line
);
157 from
[ line
].insert( header
);
159 else if( line
.substr( 0, 6 ) == "boost/" )
161 deps
[ "(unknown)" ].insert( line
);
162 from
[ line
].insert( header
);
167 struct module_primary_actions
169 virtual void heading( std::string
const & module
) = 0;
171 virtual void module_start( std::string
const & module
) = 0;
172 virtual void module_end( std::string
const & module
) = 0;
174 virtual void header_start( std::string
const & header
) = 0;
175 virtual void header_end( std::string
const & header
) = 0;
177 virtual void from_header( std::string
const & header
) = 0;
180 static fs::path
module_include_path( std::string module
)
182 std::replace( module
.begin(), module
.end(), '~', '/' );
183 return fs::path( "libs" ) / module
/ "include";
186 static fs::path
module_source_path( std::string module
)
188 std::replace( module
.begin(), module
.end(), '~', '/' );
189 return fs::path( "libs" ) / module
/ "src";
192 static fs::path
module_build_path( std::string module
)
194 std::replace( module
.begin(), module
.end(), '~', '/' );
195 return fs::path( "libs" ) / module
/ "build";
198 static fs::path
module_test_path( std::string module
)
200 std::replace( module
.begin(), module
.end(), '~', '/' );
201 return fs::path( "libs" ) / module
/ "test";
204 static void scan_module_path( fs::path
const & dir
, bool remove_prefix
, std::map
< std::string
, std::set
< std::string
> > & deps
, std::map
< std::string
, std::set
< std::string
> > & from
)
206 size_t n
= dir
.generic_string().size();
208 if( fs::exists( dir
) )
210 fs::recursive_directory_iterator
it( dir
), last
;
212 for( ; it
!= last
; ++it
)
214 if( it
->status().type() == fs::directory_file
)
219 std::string header
= it
->path().generic_string();
223 header
= header
.substr( n
+1 );
226 fs::ifstream
is( it
->path() );
228 scan_header_dependencies( header
, is
, deps
, from
);
233 static void scan_module_dependencies( std::string
const & module
, module_primary_actions
& actions
, bool track_sources
, bool track_tests
, bool include_self
)
235 // module -> [ header, header... ]
236 std::map
< std::string
, std::set
< std::string
> > deps
;
238 // header -> included from [ header, header... ]
239 std::map
< std::string
, std::set
< std::string
> > from
;
241 scan_module_path( module_include_path( module
), true, deps
, from
);
245 scan_module_path( module_source_path( module
), false, deps
, from
);
250 scan_module_path( module_test_path( module
), false, deps
, from
);
253 actions
.heading( module
);
255 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= deps
.begin(); i
!= deps
.end(); ++i
)
257 if( i
->first
== module
&& !include_self
) continue;
259 actions
.module_start( i
->first
);
261 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
263 actions
.header_start( *j
);
265 std::set
< std::string
> const & f
= from
[ *j
];
267 for( std::set
< std::string
>::const_iterator k
= f
.begin(); k
!= f
.end(); ++k
)
269 actions
.from_header( *k
);
272 actions
.header_end( *j
);
275 actions
.module_end( i
->first
);
279 // module depends on [ module, module... ]
280 static std::map
< std::string
, std::set
< std::string
> > s_module_deps
;
282 // header is included by [header, header...]
283 static std::map
< std::string
, std::set
< std::string
> > s_header_deps
;
285 // [ module, module... ] depend on module
286 static std::map
< std::string
, std::set
< std::string
> > s_reverse_deps
;
288 // header includes [header, header...]
289 static std::map
< std::string
, std::set
< std::string
> > s_header_includes
;
291 struct build_mdmap_actions
: public module_primary_actions
294 std::string module2_
;
297 void heading( std::string
const & module
)
302 void module_start( std::string
const & module
)
304 if( module
!= module_
)
306 s_module_deps
[ module_
].insert( module
);
307 s_reverse_deps
[ module
].insert( module_
);
313 void module_end( std::string
const & /*module*/ )
317 void header_start( std::string
const & header
)
322 void header_end( std::string
const & /*header*/ )
326 void from_header( std::string
const & header
)
328 if( module_
!= module2_
)
330 s_header_deps
[ header_
].insert( header
);
333 s_header_includes
[ header
].insert( header_
);
337 static void build_module_dependency_map( bool track_sources
, bool track_tests
)
339 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
341 build_mdmap_actions actions
;
342 scan_module_dependencies( *i
, actions
, track_sources
, track_tests
, true );
346 static void output_module_primary_report( std::string
const & module
, module_primary_actions
& actions
, bool track_sources
, bool track_tests
)
350 scan_module_dependencies( module
, actions
, track_sources
, track_tests
, false );
352 catch( fs::filesystem_error
const & x
)
354 std::cout
<< x
.what() << std::endl
;
358 struct module_secondary_actions
360 virtual void heading( std::string
const & module
) = 0;
362 virtual void module_start( std::string
const & module
) = 0;
363 virtual void module_end( std::string
const & module
) = 0;
365 virtual void module_adds( std::string
const & module
) = 0;
368 static void exclude( std::set
< std::string
> & x
, std::set
< std::string
> const & y
)
370 for( std::set
< std::string
>::const_iterator i
= y
.begin(); i
!= y
.end(); ++i
)
376 static void output_module_secondary_report( std::string
const & module
, std::set
< std::string
> deps
, module_secondary_actions
& actions
)
378 actions
.heading( module
);
380 deps
.insert( module
);
382 // build transitive closure
386 std::set
< std::string
> deps2( deps
);
388 for( std::set
< std::string
>::iterator i
= deps
.begin(); i
!= deps
.end(); ++i
)
390 std::set
< std::string
> deps3
= s_module_deps
[ *i
];
392 exclude( deps3
, deps
);
399 actions
.module_start( *i
);
401 for( std::set
< std::string
>::iterator j
= deps3
.begin(); j
!= deps3
.end(); ++j
)
403 actions
.module_adds( *j
);
406 actions
.module_end( *i
);
408 deps2
.insert( deps3
.begin(), deps3
.end() );
422 static void output_module_secondary_report( std::string
const & module
, module_secondary_actions
& actions
)
424 output_module_secondary_report( module
, s_module_deps
[ module
], actions
);
427 struct header_inclusion_actions
429 virtual void heading( std::string
const & header
, std::string
const & module
) = 0;
431 virtual void module_start( std::string
const & module
) = 0;
432 virtual void module_end( std::string
const & module
) = 0;
434 virtual void header( std::string
const & header
) = 0;
437 static void output_header_inclusion_report( std::string
const & header
, header_inclusion_actions
& actions
)
439 std::string module
= s_header_map
[ header
];
441 actions
.heading( header
, module
);
443 std::set
< std::string
> from
= s_header_deps
[ header
];
445 // classify 'from' dependencies by module
447 // module -> [header, header...]
448 std::map
< std::string
, std::set
< std::string
> > from2
;
450 for( std::set
< std::string
>::iterator i
= from
.begin(); i
!= from
.end(); ++i
)
452 from2
[ s_header_map
[ *i
] ].insert( *i
);
455 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= from2
.begin(); i
!= from2
.end(); ++i
)
457 actions
.module_start( i
->first
);
459 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
461 actions
.header( *j
);
464 actions
.module_end( i
->first
);
468 // output_module_primary_report
470 struct module_primary_txt_actions
: public module_primary_actions
472 void heading( std::string
const & module
)
474 std::cout
<< "Primary dependencies for " << module
<< ":\n\n";
477 void module_start( std::string
const & module
)
479 std::cout
<< module
<< ":\n";
482 void module_end( std::string
const & /*module*/ )
487 void header_start( std::string
const & header
)
489 std::cout
<< " <" << header
<< ">\n";
492 void header_end( std::string
const & /*header*/ )
496 void from_header( std::string
const & header
)
498 std::cout
<< " from <" << header
<< ">\n";
502 struct module_primary_html_actions
: public module_primary_actions
504 void heading( std::string
const & module
)
506 std::cout
<< "\n\n<h1 id=\"primary-dependencies\">Primary dependencies for <em>" << module
<< "</em></h1>\n";
509 void module_start( std::string
const & module
)
511 std::cout
<< " <h2 id=\"" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2>\n";
514 void module_end( std::string
const & /*module*/ )
518 void header_start( std::string
const & header
)
520 std::cout
<< " <h3><code><" << header
<< "></code></h3><ul>\n";
523 void header_end( std::string
const & /*header*/ )
525 std::cout
<< " </ul>\n";
528 void from_header( std::string
const & header
)
530 std::cout
<< " <li>from <code><" << header
<< "></code></li>\n";
534 static void output_module_primary_report( std::string
const & module
, bool html
, bool track_sources
, bool track_tests
)
538 module_primary_html_actions actions
;
539 output_module_primary_report( module
, actions
, track_sources
, track_tests
);
543 module_primary_txt_actions actions
;
544 output_module_primary_report( module
, actions
, track_sources
, track_tests
);
548 // output_module_secondary_report
550 struct module_secondary_txt_actions
: public module_secondary_actions
552 void heading( std::string
const & module
)
554 std::cout
<< "Secondary dependencies for " << module
<< ":\n\n";
557 void module_start( std::string
const & module
)
559 std::cout
<< module
<< ":\n";
562 void module_end( std::string
const & /*module*/ )
567 void module_adds( std::string
const & module
)
569 std::cout
<< " adds " << module
<< "\n";
573 struct module_secondary_html_actions
: public module_secondary_actions
577 void heading( std::string
const & module
)
579 std::cout
<< "\n\n<h1 id=\"secondary-dependencies\">Secondary dependencies for <em>" << module
<< "</em></h1>\n";
582 void module_start( std::string
const & module
)
584 std::cout
<< " <h2><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
588 void module_end( std::string
const & /*module*/ )
590 std::cout
<< " </ul>\n";
593 void module_adds( std::string
const & module
)
595 std::cout
<< " <li><a href=\"" << m2_
<< ".html#" << module
<< "\">adds <em>" << module
<< "</em></a></li>\n";
599 static void output_module_secondary_report( std::string
const & module
, bool html
)
603 module_secondary_html_actions actions
;
604 output_module_secondary_report( module
, actions
);
608 module_secondary_txt_actions actions
;
609 output_module_secondary_report( module
, actions
);
613 // output_header_report
615 struct header_inclusion_txt_actions
: public header_inclusion_actions
617 void heading( std::string
const & header
, std::string
const & module
)
619 std::cout
<< "Inclusion report for <" << header
<< "> (in module " << module
<< "):\n\n";
622 void module_start( std::string
const & module
)
624 std::cout
<< " from " << module
<< ":\n";
627 void module_end( std::string
const & /*module*/ )
632 void header( std::string
const & header
)
634 std::cout
<< " <" << header
<< ">\n";
638 struct header_inclusion_html_actions
: public header_inclusion_actions
640 void heading( std::string
const & header
, std::string
const & module
)
642 std::cout
<< "<h1>Inclusion report for <code><" << header
<< "></code> (in module <em>" << module
<< "</em>)</h1>\n";
645 void module_start( std::string
const & module
)
647 std::cout
<< " <h2>From <a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
650 void module_end( std::string
const & /*module*/ )
652 std::cout
<< " </ul>\n";
655 void header( std::string
const & header
)
657 std::cout
<< " <li><code><" << header
<< "></code></li>\n";
661 static void output_header_report( std::string
const & header
, bool html
)
665 header_inclusion_html_actions actions
;
666 output_header_inclusion_report( header
, actions
);
670 header_inclusion_txt_actions actions
;
671 output_header_inclusion_report( header
, actions
);
675 // output_module_reverse_report
677 struct module_reverse_actions
679 virtual void heading( std::string
const & module
) = 0;
681 virtual void module_start( std::string
const & module
) = 0;
682 virtual void module_end( std::string
const & module
) = 0;
684 virtual void header_start( std::string
const & header
) = 0;
685 virtual void header_end( std::string
const & header
) = 0;
687 virtual void from_header( std::string
const & header
) = 0;
690 static void output_module_reverse_report( std::string
const & module
, module_reverse_actions
& actions
)
692 actions
.heading( module
);
694 std::set
< std::string
> const from
= s_reverse_deps
[ module
];
696 for( std::set
< std::string
>::const_iterator i
= from
.begin(); i
!= from
.end(); ++i
)
698 actions
.module_start( *i
);
700 for( std::map
< std::string
, std::set
< std::string
> >::iterator j
= s_header_deps
.begin(); j
!= s_header_deps
.end(); ++j
)
702 if( s_header_map
[ j
->first
] == module
)
704 bool header_started
= false;
706 for( std::set
< std::string
>::iterator k
= j
->second
.begin(); k
!= j
->second
.end(); ++k
)
708 if( s_header_map
[ *k
] == *i
)
710 if( !header_started
)
712 actions
.header_start( j
->first
);
714 header_started
= true;
717 actions
.from_header( *k
);
723 actions
.header_end( j
->first
);
728 actions
.module_end( *i
);
732 struct module_reverse_txt_actions
: public module_reverse_actions
734 void heading( std::string
const & module
)
736 std::cout
<< "Reverse dependencies for " << module
<< ":\n\n";
739 void module_start( std::string
const & module
)
741 std::cout
<< module
<< ":\n";
744 void module_end( std::string
const & /*module*/ )
749 void header_start( std::string
const & header
)
751 std::cout
<< " <" << header
<< ">\n";
754 void header_end( std::string
const & /*header*/ )
758 void from_header( std::string
const & header
)
760 std::cout
<< " from <" << header
<< ">\n";
764 struct module_reverse_html_actions
: public module_reverse_actions
766 void heading( std::string
const & module
)
768 std::cout
<< "\n\n<h1 id=\"reverse-dependencies\">Reverse dependencies for <em>" << module
<< "</em></h1>\n";
771 void module_start( std::string
const & module
)
773 std::cout
<< " <h2 id=\"reverse-" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2>\n";
776 void module_end( std::string
const & /*module*/ )
780 void header_start( std::string
const & header
)
782 std::cout
<< " <h3><code><" << header
<< "></code></h3><ul>\n";
785 void header_end( std::string
const & /*header*/ )
787 std::cout
<< " </ul>\n";
790 void from_header( std::string
const & header
)
792 std::cout
<< " <li>from <code><" << header
<< "></code></li>\n";
796 static void output_module_reverse_report( std::string
const & module
, bool html
)
800 module_reverse_html_actions actions
;
801 output_module_reverse_report( module
, actions
);
805 module_reverse_txt_actions actions
;
806 output_module_reverse_report( module
, actions
);
810 // module_level_report
812 int const unknown_level
= INT_MAX
/ 2;
814 struct module_level_actions
816 virtual void begin() = 0;
817 virtual void end() = 0;
819 virtual void level_start( int level
) = 0;
820 virtual void level_end( int level
) = 0;
822 virtual void module_start( std::string
const & module
) = 0;
823 virtual void module_end( std::string
const & module
) = 0;
825 virtual void module2( std::string
const & module
, int level
) = 0;
828 static void output_module_level_report( module_level_actions
& actions
)
830 // build module level map
832 std::map
< std::string
, int > level_map
;
834 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
836 if( s_module_deps
[ *i
].empty() )
839 // std::cerr << *i << ": " << 0 << std::endl;
843 level_map
[ *i
] = unknown_level
;
847 // build transitive closure to see through cycles
849 std::map
< std::string
, std::set
< std::string
> > deps2
= s_module_deps
;
858 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= deps2
.begin(); i
!= deps2
.end(); ++i
)
860 std::set
< std::string
> tmp
= i
->second
;
862 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
864 std::set
< std::string
> tmp2
= deps2
[ *j
];
865 tmp
.insert( tmp2
.begin(), tmp2
.end() );
868 if( tmp
.size() != i
->second
.size() )
878 // compute acyclic levels
880 for( int k
= 1, n
= s_modules
.size(); k
< n
; ++k
)
882 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= s_module_deps
.begin(); i
!= s_module_deps
.end(); ++i
)
884 // i->first depends on i->second
886 if( level_map
[ i
->first
] >= unknown_level
)
890 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
892 level
= std::max( level
, level_map
[ *j
] + 1 );
897 level_map
[ i
->first
] = level
;
898 // std::cerr << i->first << ": " << level << std::endl;
904 // min_level_map[ M ] == L means the level is unknown, but at least L
905 std::map
< std::string
, int > min_level_map
;
907 // initialize min_level_map for acyclic dependencies
909 for( std::map
< std::string
, int >::iterator i
= level_map
.begin(); i
!= level_map
.end(); ++i
)
911 if( i
->second
< unknown_level
)
913 min_level_map
[ i
->first
] = i
->second
;
917 // compute levels for cyclic modules
919 for( int k
= 1, n
= s_modules
.size(); k
< n
; ++k
)
921 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= s_module_deps
.begin(); i
!= s_module_deps
.end(); ++i
)
923 if( level_map
[ i
->first
] >= unknown_level
)
927 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
929 int jl
= level_map
[ *j
];
931 if( jl
< unknown_level
)
933 level
= std::max( level
, jl
+ 1 );
937 int ml
= min_level_map
[ *j
];
939 if( deps2
[ *j
].count( i
->first
) == 0 )
941 // *j does not depend on i->first, so
942 // the level of i->first is at least
943 // 1 + the minimum level of *j
948 level
= std::max( level
, ml
);
952 min_level_map
[ i
->first
] = level
;
959 std::map
< int, std::set
< std::string
> > reverse_level_map
;
961 for( std::map
< std::string
, int >::iterator i
= level_map
.begin(); i
!= level_map
.end(); ++i
)
963 int level
= i
->second
;
965 if( level
>= unknown_level
)
967 int min_level
= min_level_map
[ i
->first
];
975 reverse_level_map
[ level
].insert( i
->first
);
982 for( std::map
< int, std::set
< std::string
> >::iterator i
= reverse_level_map
.begin(); i
!= reverse_level_map
.end(); ++i
)
984 actions
.level_start( i
->first
);
986 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
988 actions
.module_start( *j
);
990 std::set
< std::string
> mdeps
= s_module_deps
[ *j
];
992 for( std::set
< std::string
>::iterator k
= mdeps
.begin(); k
!= mdeps
.end(); ++k
)
994 int level
= level_map
[ *k
];
996 if( level
>= unknown_level
)
998 int min_level
= min_level_map
[ *k
];
1000 if( min_level
!= 0 )
1006 actions
.module2( *k
, level
);
1009 actions
.module_end( *j
);
1012 actions
.level_end( i
->first
);
1018 struct module_level_txt_actions
: public module_level_actions
1024 std::cout
<< "Module Levels:\n\n";
1031 void level_start( int level
)
1033 if( level
>= unknown_level
)
1035 std::cout
<< "Level (undetermined):\n";
1039 std::cout
<< "Level " << level
<< ":\n";
1045 void level_end( int /*level*/ )
1050 void module_start( std::string
const & module
)
1052 std::cout
<< " " << module
;
1060 void module_end( std::string
const & /*module*/ )
1065 void module2( std::string
const & module
, int level
)
1067 std::cout
<< " " << module
<< "(";
1069 if( level
>= unknown_level
)
1082 struct module_level_html_actions
: public module_level_actions
1088 std::cout
<< "<div id='module-levels'><h1>Module Levels</h1>\n";
1093 std::cout
<< "</div>\n";
1096 void level_start( int level
)
1098 if( level
>= unknown_level
)
1100 std::cout
<< " <h2>Level <em>undetermined</em></h2>\n";
1104 std::cout
<< " <h2 id='level:" << level
<< "'>Level " << level
<< "</h2>\n";
1110 void level_end( int /*level*/ )
1114 void module_start( std::string
const & module
)
1116 std::cout
<< " <h3 id='" << module
<< "'><a href=\"" << module
<< ".html\">" << module
<< "</a></h3><p class='primary-list'>";
1119 void module_end( std::string
const & /*module*/ )
1121 std::cout
<< "</p>\n";
1124 void module2( std::string
const & module
, int level
)
1128 bool important
= level
< unknown_level
&& level
> 1 && level
>= level_
- 1;
1132 std::cout
<< "<strong>";
1135 std::cout
<< module
;
1137 if( level
< unknown_level
)
1139 std::cout
<< "<sup>" << level
<< "</sup>";
1144 std::cout
<< "</strong>";
1149 static void output_module_level_report( bool html
)
1153 module_level_html_actions actions
;
1154 output_module_level_report( actions
);
1158 module_level_txt_actions actions
;
1159 output_module_level_report( actions
);
1163 // module_overview_report
1165 struct module_overview_actions
1167 virtual void begin() = 0;
1168 virtual void end() = 0;
1170 virtual void module_start( std::string
const & module
) = 0;
1171 virtual void module_end( std::string
const & module
) = 0;
1173 virtual void module2( std::string
const & module
) = 0;
1176 static void output_module_overview_report( module_overview_actions
& actions
)
1180 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1182 actions
.module_start( *i
);
1184 std::set
< std::string
> const mdeps
= s_module_deps
[ *i
];
1186 for( std::set
< std::string
>::const_iterator j
= mdeps
.begin(); j
!= mdeps
.end(); ++j
)
1188 actions
.module2( *j
);
1191 actions
.module_end( *i
);
1197 struct module_overview_txt_actions
: public module_overview_actions
1203 std::cout
<< "Module Overview:\n\n";
1210 void module_start( std::string
const & module
)
1212 std::cout
<< module
;
1216 void module_end( std::string
const & /*module*/ )
1221 void module2( std::string
const & module
)
1229 std::cout
<< " " << module
;
1233 struct module_overview_html_actions
: public module_overview_actions
1237 std::cout
<< "<div id='module-overview'><h1>Module Overview</h1>\n";
1242 std::cout
<< "</div>\n";
1245 void module_start( std::string
const & module
)
1247 std::cout
<< " <h2 id='" << module
<< "'><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><p class='primary-list'>";
1250 void module_end( std::string
const & /*module*/ )
1252 std::cout
<< "</p>\n";
1255 void module2( std::string
const & module
)
1257 std::cout
<< " " << module
;
1261 static void output_module_overview_report( bool html
)
1265 module_overview_html_actions actions
;
1266 output_module_overview_report( actions
);
1270 module_overview_txt_actions actions
;
1271 output_module_overview_report( actions
);
1275 // list_dependencies
1277 struct list_dependencies_actions
: public module_overview_actions
1287 void module_start( std::string
const & module
)
1289 std::cout
<< module
<< " ->";
1292 void module_end( std::string
const & /*module*/ )
1297 void module2( std::string
const & module
)
1299 if( module
!= "(unknown)" )
1301 std::cout
<< " " << module
;
1306 static void list_dependencies()
1308 list_dependencies_actions actions
;
1309 output_module_overview_report( actions
);
1314 static void output_html_header( std::string
const & title
, std::string
const & stylesheet
, std::string
const & prefix
)
1316 std::cout
<< "<html>\n";
1317 std::cout
<< "<head>\n";
1318 std::cout
<< "<title>" << title
<< "</title>\n";
1320 if( !stylesheet
.empty() )
1322 std::cout
<< "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet
<< "\" />\n";
1325 std::cout
<< "</head>\n";
1326 std::cout
<< "<body>\n";
1328 if( !prefix
.empty() )
1330 std::cout
<< prefix
<< std::endl
;
1334 static void output_html_footer( std::string
const & footer
)
1336 std::cout
<< "<hr />\n";
1337 std::cout
<< "<p class=\"footer\">" << footer
<< "</p>\n";
1338 std::cout
<< "</body>\n";
1339 std::cout
<< "</html>\n";
1342 static void enable_secondary( bool & secondary
, bool track_sources
, bool track_tests
)
1348 build_module_dependency_map( track_sources
, track_tests
);
1350 catch( fs::filesystem_error
const & x
)
1352 std::cout
<< x
.what() << std::endl
;
1359 static void list_modules()
1361 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1363 std::cout
<< *i
<< "\n";
1367 static void list_buildable()
1369 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1371 if( fs::exists( module_build_path( *i
) ) && fs::exists( module_source_path( *i
) ) )
1373 std::cout
<< *i
<< "\n";
1378 // module_weight_report
1380 struct module_weight_actions
1382 virtual void begin() = 0;
1383 virtual void end() = 0;
1385 virtual void weight_start( int weight
) = 0;
1386 virtual void weight_end( int weight
) = 0;
1388 virtual void module_start( std::string
const & module
) = 0;
1389 virtual void module_end( std::string
const & module
) = 0;
1391 virtual void module_primary_start() = 0;
1392 virtual void module_primary( std::string
const & module
, int weight
) = 0;
1393 virtual void module_primary_end() = 0;
1395 virtual void module_secondary_start() = 0;
1396 virtual void module_secondary( std::string
const & module
, int weight
) = 0;
1397 virtual void module_secondary_end() = 0;
1400 static void output_module_weight_report( module_weight_actions
& actions
)
1402 // gather secondary dependencies
1404 struct build_secondary_deps
: public module_secondary_actions
1406 std::map
< std::string
, std::set
< std::string
> > * pm_
;
1408 build_secondary_deps( std::map
< std::string
, std::set
< std::string
> > * pm
): pm_( pm
)
1412 std::string module_
;
1414 void heading( std::string
const & module
)
1419 void module_start( std::string
const & /*module*/ )
1423 void module_end( std::string
const & /*module*/ )
1427 void module_adds( std::string
const & module
)
1429 (*pm_
)[ module_
].insert( module
);
1433 std::map
< std::string
, std::set
< std::string
> > secondary_deps
;
1435 build_secondary_deps
bsd( &secondary_deps
);
1437 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1439 output_module_secondary_report( *i
, bsd
);
1444 std::map
< int, std::set
< std::string
> > modules_by_weight
;
1446 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1448 int w
= s_module_deps
[ *i
].size() + secondary_deps
[ *i
].size();
1449 modules_by_weight
[ w
].insert( *i
);
1456 for( std::map
< int, std::set
< std::string
> >::const_iterator i
= modules_by_weight
.begin(); i
!= modules_by_weight
.end(); ++i
)
1458 actions
.weight_start( i
->first
);
1460 for( std::set
< std::string
>::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1462 actions
.module_start( *j
);
1464 if( !s_module_deps
[ *j
].empty() )
1466 actions
.module_primary_start();
1468 for( std::set
< std::string
>::const_iterator k
= s_module_deps
[ *j
].begin(); k
!= s_module_deps
[ *j
].end(); ++k
)
1470 int w
= s_module_deps
[ *k
].size() + secondary_deps
[ *k
].size();
1471 actions
.module_primary( *k
, w
);
1474 actions
.module_primary_end();
1477 if( !secondary_deps
[ *j
].empty() )
1479 actions
.module_secondary_start();
1481 for( std::set
< std::string
>::const_iterator k
= secondary_deps
[ *j
].begin(); k
!= secondary_deps
[ *j
].end(); ++k
)
1483 int w
= s_module_deps
[ *k
].size() + secondary_deps
[ *k
].size();
1484 actions
.module_secondary( *k
, w
);
1487 actions
.module_secondary_end();
1490 actions
.module_end( *j
);
1493 actions
.weight_end( i
->first
);
1499 struct module_weight_txt_actions
: public module_weight_actions
1503 std::cout
<< "Module Weights:\n\n";
1510 void weight_start( int weight
)
1512 std::cout
<< "Weight " << weight
<< ":\n";
1515 void weight_end( int /*weight*/ )
1520 void module_start( std::string
const & module
)
1522 std::cout
<< " " << module
;
1525 void module_end( std::string
const & /*module*/ )
1530 void module_primary_start()
1535 void module_primary( std::string
const & module
, int weight
)
1537 std::cout
<< " " << module
<< "(" << weight
<< ")";
1540 void module_primary_end()
1544 void module_secondary_start()
1549 void module_secondary( std::string
const & module
, int /*weight*/ )
1551 std::cout
<< " " << module
;
1554 void module_secondary_end()
1559 struct module_weight_html_actions
: public module_weight_actions
1565 std::cout
<< "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
1570 std::cout
<< "</div>\n";
1573 void weight_start( int weight
)
1575 std::cout
<< " <h2 id='weight:" << weight
<< "'>Weight " << weight
<< "</h2>\n";
1579 void weight_end( int /*weight*/ )
1583 void module_start( std::string
const & module
)
1585 std::cout
<< " <h3 id='" << module
<< "'><a href=\"" << module
<< ".html\">" << module
<< "</a></h3>";
1588 void module_end( std::string
const & /*module*/ )
1593 void module_primary_start()
1595 std::cout
<< "<p class='primary-list'>";
1598 void module_primary( std::string
const & module
, int weight
)
1602 bool heavy
= weight
>= 0.8 * weight_
;
1606 std::cout
<< "<strong>";
1609 std::cout
<< module
<< "<sup>" << weight
<< "</sup>";
1613 std::cout
<< "</strong>";
1617 void module_primary_end()
1619 std::cout
<< "</p>";
1622 void module_secondary_start()
1624 std::cout
<< "<p class='secondary-list'>";
1627 void module_secondary( std::string
const & module
, int /*weight*/ )
1629 std::cout
<< " " << module
;
1632 void module_secondary_end()
1634 std::cout
<< "</p>";
1638 static void output_module_weight_report( bool html
)
1642 module_weight_html_actions actions
;
1643 output_module_weight_report( actions
);
1647 module_weight_txt_actions actions
;
1648 output_module_weight_report( actions
);
1652 // output_module_subset_report
1654 struct module_subset_actions
1656 virtual void heading( std::string
const & module
) = 0;
1658 virtual void module_start( std::string
const & module
) = 0;
1659 virtual void module_end( std::string
const & module
) = 0;
1661 virtual void from_path( std::vector
<std::string
> const & path
) = 0;
1664 static void add_module_headers( fs::path
const & dir
, std::set
<std::string
> & headers
)
1666 if( fs::exists( dir
) )
1668 fs::recursive_directory_iterator
it( dir
), last
;
1670 for( ; it
!= last
; ++it
)
1672 if( it
->status().type() == fs::directory_file
)
1677 headers
.insert( it
->path().generic_string() );
1682 static void output_module_subset_report_( std::string
const & module
, std::set
<std::string
> const & headers
, module_subset_actions
& actions
)
1684 // build header closure
1686 // header -> (header)*
1687 std::map
< std::string
, std::set
<std::string
> > inc2
;
1689 // (header, header) -> path
1690 std::map
< std::pair
<std::string
, std::string
>, std::vector
<std::string
> > paths
;
1692 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
1694 std::set
<std::string
> & s
= inc2
[ *i
];
1696 s
= s_header_includes
[ *i
];
1698 for( std::set
<std::string
>::const_iterator j
= s
.begin(); j
!= s
.end(); ++j
)
1700 std::vector
<std::string
> & v
= paths
[ std::make_pair( *i
, *j
) ];
1712 for( std::map
< std::string
, std::set
<std::string
> >::iterator i
= inc2
.begin(); i
!= inc2
.end(); ++i
)
1714 std::set
<std::string
> & s2
= i
->second
;
1716 for( std::set
<std::string
>::const_iterator j
= s2
.begin(); j
!= s2
.end(); ++j
)
1718 std::set
<std::string
> const & s
= s_header_includes
[ *j
];
1720 for( std::set
<std::string
>::const_iterator k
= s
.begin(); k
!= s
.end(); ++k
)
1722 if( s2
.count( *k
) == 0 )
1726 std::vector
<std::string
> const & v1
= paths
[ std::make_pair( i
->first
, *j
) ];
1727 std::vector
<std::string
> & v2
= paths
[ std::make_pair( i
->first
, *k
) ];
1741 // module -> header -> path [header -> header -> header]
1742 std::map
< std::string
, std::map
< std::string
, std::vector
<std::string
> > > subset
;
1744 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
1746 std::set
<std::string
> const & s
= inc2
[ *i
];
1748 for( std::set
<std::string
>::const_iterator j
= s
.begin(); j
!= s
.end(); ++j
)
1750 std::string
const & m
= s_header_map
[ *j
];
1752 if( m
.empty() ) continue;
1754 std::vector
<std::string
> const & path
= paths
[ std::make_pair( *i
, *j
) ];
1756 if( subset
.count( m
) == 0 || subset
[ m
].count( *i
) == 0 || subset
[ m
][ *i
].size() > path
.size() )
1758 subset
[ m
][ *i
] = path
;
1763 actions
.heading( module
);
1765 for( std::map
< std::string
, std::map
< std::string
, std::vector
<std::string
> > >::const_iterator i
= subset
.begin(); i
!= subset
.end(); ++i
)
1767 if( i
->first
== module
) continue;
1769 actions
.module_start( i
->first
);
1773 for( std::map
< std::string
, std::vector
<std::string
> >::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end() && k
< 4; ++j
, ++k
)
1775 actions
.from_path( j
->second
);
1778 actions
.module_end( i
->first
);
1782 static void output_module_subset_report( std::string
const & module
, bool track_sources
, bool track_tests
, module_subset_actions
& actions
)
1784 std::set
<std::string
> headers
= s_module_headers
[ module
];
1788 add_module_headers( module_source_path( module
), headers
);
1793 add_module_headers( module_test_path( module
), headers
);
1796 output_module_subset_report_( module
, headers
, actions
);
1799 struct module_subset_txt_actions
: public module_subset_actions
1801 void heading( std::string
const & module
)
1803 std::cout
<< "Subset dependencies for " << module
<< ":\n\n";
1806 void module_start( std::string
const & module
)
1808 std::cout
<< module
<< ":\n";
1811 void module_end( std::string
const & /*module*/ )
1816 void from_path( std::vector
<std::string
> const & path
)
1818 for( std::vector
<std::string
>::const_iterator i
= path
.begin(); i
!= path
.end(); ++i
)
1820 if( i
== path
.begin() )
1826 std::cout
<< " -> ";
1836 struct module_subset_html_actions
: public module_subset_actions
1838 void heading( std::string
const & module
)
1840 std::cout
<< "\n\n<h1 id=\"subset-dependencies\">Subset dependencies for <em>" << module
<< "</em></h1>\n";
1843 void module_start( std::string
const & module
)
1845 std::cout
<< " <h2 id=\"subset-" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
1848 void module_end( std::string
const & /*module*/ )
1850 std::cout
<< "</ul>\n";
1853 void from_path( std::vector
<std::string
> const & path
)
1855 std::cout
<< " <li>";
1857 for( std::vector
<std::string
>::const_iterator i
= path
.begin(); i
!= path
.end(); ++i
)
1859 if( i
!= path
.begin() )
1861 std::cout
<< " ⇢ ";
1864 std::cout
<< "<code>" << *i
<< "</code>";
1867 std::cout
<< "</li>\n";
1871 static void output_module_subset_report( std::string
const & module
, bool track_sources
, bool track_tests
, bool html
)
1875 module_subset_html_actions actions
;
1876 output_module_subset_report( module
, track_sources
, track_tests
, actions
);
1880 module_subset_txt_actions actions
;
1881 output_module_subset_report( module
, track_sources
, track_tests
, actions
);
1885 // --list-exceptions
1887 static void list_exceptions()
1891 for( std::map
< std::string
, std::set
<std::string
> >::const_iterator i
= s_module_headers
.begin(); i
!= s_module_headers
.end(); ++i
)
1893 std::string module
= i
->first
;
1895 std::replace( module
.begin(), module
.end(), '~', '/' );
1897 std::string
const prefix
= "boost/" + module
;
1898 size_t const n
= prefix
.size();
1900 for( std::set
< std::string
>::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1902 std::string
const & header
= *j
;
1904 if( header
.substr( 0, n
+1 ) != prefix
+ '/' && header
!= prefix
+ ".hpp" )
1908 std::cout
<< module
<< ":\n";
1912 std::cout
<< " " << header
<< '\n';
1920 struct module_test_primary_actions
: public module_primary_actions
1922 std::set
< std::string
> & m_
;
1924 module_test_primary_actions( std::set
< std::string
> & m
): m_( m
)
1928 void heading( std::string
const & module
)
1930 std::cout
<< "Test dependencies for " << module
<< ":\n\n";
1933 void module_start( std::string
const & module
)
1935 std::cout
<< module
<< "\n";
1936 m_
.insert( module
);
1939 void module_end( std::string
const & /*module*/ )
1943 void header_start( std::string
const & /*header*/ )
1947 void header_end( std::string
const & /*header*/ )
1951 void from_header( std::string
const & /*header*/ )
1956 struct module_test_secondary_actions
: public module_secondary_actions
1958 std::set
< std::string
> & m_
;
1961 module_test_secondary_actions( std::set
< std::string
> & m
): m_( m
)
1965 void heading( std::string
const & /*module*/ )
1969 void module_start( std::string
const & module
)
1974 void module_end( std::string
const & /*module*/ )
1978 void module_adds( std::string
const & module
)
1980 if( m_
.count( module
) == 0 )
1982 std::cout
<< module
<< " (from " << m2_
<< ")\n";
1983 m_
.insert( module
);
1988 static void output_module_test_report( std::string
const & module
)
1990 std::set
< std::string
> m
;
1992 module_test_primary_actions
a1( m
);
1993 output_module_primary_report( module
, a1
, true, true );
1997 bool secondary
= false;
1998 enable_secondary( secondary
, true, false );
2000 std::set
< std::string
> m2( m
);
2001 m2
.insert( module
);
2003 module_test_secondary_actions
a2( m2
);
2005 output_module_secondary_report( module
, m
, a2
);
2010 struct collect_primary_dependencies
: public module_primary_actions
2012 std::set
< std::string
> set_
;
2014 void heading( std::string
const & )
2018 void module_start( std::string
const & module
)
2020 if( module
== "(unknown)" ) return;
2022 set_
.insert( module
);
2025 void module_end( std::string
const & /*module*/ )
2029 void header_start( std::string
const & /*header*/ )
2033 void header_end( std::string
const & /*header*/ )
2037 void from_header( std::string
const & /*header*/ )
2042 static std::string
module_cmake_name( std::string module
)
2044 std::replace( module
.begin(), module
.end(), '~', '_' );
2048 static void output_module_cmake_report( std::string module
)
2050 std::cout
<< "# Generated by `boostdep --cmake " << module
<< "`\n\n";
2052 std::replace( module
.begin(), module
.end(), '/', '~' );
2054 collect_primary_dependencies a1
;
2055 output_module_primary_report( module
, a1
, false, false );
2057 if( !fs::exists( module_source_path( module
) ) )
2059 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2061 std::cout
<< "boost_declare_dependency(INTERFACE " << module_cmake_name( *i
) << ")\n";
2066 collect_primary_dependencies a2
;
2067 output_module_primary_report( module
, a2
, true, false );
2069 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2071 a2
.set_
.erase( *i
);
2072 std::cout
<< "boost_declare_dependency(PUBLIC " << module_cmake_name( *i
) << ")\n";
2077 for( std::set
< std::string
>::const_iterator i
= a2
.set_
.begin(); i
!= a2
.set_
.end(); ++i
)
2079 std::cout
<< "boost_declare_dependency(PRIVATE " << module_cmake_name( *i
) << ")\n";
2084 // --list-missing-headers
2086 struct missing_header_actions
: public module_primary_actions
2088 std::string module_
, module2_
;
2090 void heading( std::string
const & module
)
2095 void module_start( std::string
const & module
)
2100 void module_end( std::string
const & /*module*/ )
2104 void header_start( std::string
const & header
)
2106 if( module2_
== "(unknown)" )
2108 if( !module_
.empty() )
2110 std::cout
<< module_
<< ":\n";
2114 std::cout
<< " <" << header
<< ">\n";
2118 void header_end( std::string
const & /*header*/ )
2122 void from_header( std::string
const & header
)
2124 if( module2_
== "(unknown)" )
2126 std::cout
<< " from <" << header
<< ">\n";
2131 static void list_missing_headers( std::string
const & module
)
2133 missing_header_actions a
;
2134 output_module_primary_report( module
, a
, false, false );
2137 static void list_missing_headers()
2139 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
2141 list_missing_headers( *i
);
2147 struct primary_pkgconfig_actions
: public module_primary_actions
2149 std::string version_
;
2152 void heading( std::string
const & )
2156 void module_start( std::string
const & module
)
2158 if( module
== "(unknown)" ) return;
2160 std::string
m2( module
);
2161 std::replace( m2
.begin(), m2
.end(), '~', '_' );
2163 if( !list_
.empty() )
2168 list_
+= "boost_" + m2
+ " = " + version_
;
2171 void module_end( std::string
const & )
2175 void header_start( std::string
const & )
2179 void header_end( std::string
const & )
2183 void from_header( std::string
const & )
2188 static void output_requires( std::string
const & section
, std::string
const & version
, std::set
< std::string
> const & s
)
2192 for( std::set
< std::string
>::const_iterator i
= s
.begin(); i
!= s
.end(); ++i
)
2196 std::cout
<< section
<< ": ";
2204 std::string
m2( *i
);
2205 std::replace( m2
.begin(), m2
.end(), '~', '_' );
2207 std::cout
<< "boost_" << m2
<< " = " << version
;
2211 static void output_pkgconfig( std::string
const & module
, std::string
const & version
, int argc
, char const* argv
[] )
2213 for( int i
= 0; i
< argc
; ++i
)
2215 std::cout
<< argv
[ i
] << '\n';
2220 std::string
m2( module
);
2221 std::replace( m2
.begin(), m2
.end(), '/', '_' );
2223 std::string
m3( module
);
2224 std::replace( m3
.begin(), m3
.end(), '/', '~' );
2226 std::cout
<< "Name: boost_" << module
<< '\n';
2227 std::cout
<< "Description: Boost C++ library '" << module
<< "'\n";
2228 std::cout
<< "Version: " << version
<< '\n';
2229 std::cout
<< "URL: http://www.boost.org/libs/" << module
<< '\n';
2230 std::cout
<< "Cflags: -I${includedir}\n";
2232 if( fs::exists( module_build_path( module
) ) && fs::exists( module_source_path( module
) ) )
2234 std::cout
<< "Libs: -L${libdir} -lboost_" << m2
<< "\n";
2237 collect_primary_dependencies a1
;
2238 output_module_primary_report( m3
, a1
, false, false );
2240 if( !a1
.set_
.empty() )
2242 output_requires( "Requires", version
, a1
.set_
);
2243 std::cout
<< std::endl
;
2246 collect_primary_dependencies a2
;
2247 output_module_primary_report( m3
, a2
, true, false );
2249 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2251 a2
.set_
.erase( *i
);
2254 if( !a2
.set_
.empty() )
2256 output_requires( "Requires.private", version
, a2
.set_
);
2257 std::cout
<< std::endl
;
2263 static void output_directory_subset_report( std::string
const & module
, std::set
<std::string
> const & headers
, bool html
)
2265 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
2267 std::map
< std::string
, std::set
< std::string
> > deps
;
2268 std::map
< std::string
, std::set
< std::string
> > from
;
2270 std::ifstream
is( i
->c_str() );
2271 scan_header_dependencies( *i
, is
, deps
, from
);
2273 for( std::map
< std::string
, std::set
< std::string
> >::const_iterator j
= from
.begin(); j
!= from
.end(); ++j
)
2275 for( std::set
<std::string
>::const_iterator k
= j
->second
.begin(); k
!= j
->second
.end(); ++k
)
2277 s_header_includes
[ *k
].insert( j
->first
);
2284 module_subset_html_actions actions
;
2285 output_module_subset_report_( module
, headers
, actions
);
2289 module_subset_txt_actions actions
;
2290 output_module_subset_report_( module
, headers
, actions
);
2294 // list_buildable_dependencies
2296 struct list_buildable_dependencies_actions
: public module_overview_actions
2298 std::set
< std::string
> buildable_
;
2300 std::set
< std::string
> deps_
;
2303 list_buildable_dependencies_actions(): headers_()
2309 std::cout
<< "# Generated by `boostdep --list-buildable-dependencies`\n\n";
2316 void module_start( std::string
const & module
)
2321 if( buildable_
.count( module
) )
2323 std::cout
<< module
<< " =";
2327 void module_end( std::string
const & module
)
2329 if( buildable_
.count( module
) )
2333 std::cout
<< " headers";
2336 for( std::set
< std::string
>::iterator i
= deps_
.begin(); i
!= deps_
.end(); ++i
)
2338 std::cout
<< " " << *i
;
2341 std::cout
<< " ;\n";
2345 void module2( std::string
const & module
)
2347 if( module
== "(unknown)" ) return;
2349 if( buildable_
.count( module
) == 0 )
2355 deps_
.insert( module
);
2360 static void list_buildable_dependencies()
2362 list_buildable_dependencies_actions actions
;
2364 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
2366 if( fs::exists( module_build_path( *i
) ) && fs::exists( module_source_path( *i
) ) )
2368 actions
.buildable_
.insert( *i
);
2372 output_module_overview_report( actions
);
2377 static bool find_boost_root()
2379 for( int i
= 0; i
< 32; ++i
)
2381 if( fs::exists( "Jamroot" ) )
2386 fs::path p
= fs::current_path();
2388 if( p
== p
.root_path() )
2393 fs::current_path( p
.parent_path() );
2399 static bool is_boost_root( fs::path
const & p
)
2401 return fs::exists( p
/ "Jamroot" );
2406 class teebuf
: public std::streambuf
2410 std::streambuf
* sb1_
;
2411 std::streambuf
* sb2_
;
2415 teebuf( std::streambuf
* sb1
, std::streambuf
* sb2
): sb1_( sb1
), sb2_( sb2
)
2421 virtual int overflow( int c
)
2423 int r1
= sb1_
->sputc( c
);
2424 int r2
= sb2_
->sputc( c
);
2426 return r1
== EOF
|| r2
== EOF
? EOF
: c
;
2431 int r1
= sb1_
->pubsync();
2432 int r2
= sb2_
->pubsync();
2434 return r1
== 0 && r2
== 0? 0 : -1;
2440 class save_cout_rdbuf
2444 std::streambuf
* sb_
;
2448 save_cout_rdbuf(): sb_( std::cout
.rdbuf() )
2454 std::cout
.rdbuf( sb_
);
2460 int main( int argc
, char const* argv
[] )
2468 " boostdep --list-modules\n"
2469 " boostdep --list-buildable\n"
2470 " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
2471 " boostdep --list-exceptions\n"
2472 " boostdep --list-missing-headers\n"
2473 " boostdep --list-buildable-dependencies\n"
2475 " boostdep [options] --module-overview\n"
2476 " boostdep [options] --module-levels\n"
2477 " boostdep [options] --module-weights\n"
2479 " boostdep [options] [--primary] <module>\n"
2480 " boostdep [options] --secondary <module>\n"
2481 " boostdep [options] --reverse <module>\n"
2482 " boostdep [options] --subset <module>\n"
2483 " boostdep [options] [--header] <header>\n"
2484 " boostdep --test <module>\n"
2485 " boostdep --cmake <module>\n"
2486 " boostdep --pkgconfig <module> <version> [<var>=<value>] [<var>=<value>]...\n"
2487 " boostdep [options] --subset-for <directory>\n"
2489 " [options]: [--boost-root <path-to-boost>]\n"
2490 " [--[no-]track-sources] [--[no-]track-tests]\n"
2491 " [--html-title <title>] [--html-footer <footer>]\n"
2492 " [--html-stylesheet <stylesheet>] [--html-prefix <prefix>]\n"
2498 bool root_set
= false;
2500 for( int i
= 0; i
< argc
; ++i
)
2502 std::string option
= argv
[ i
];
2504 if( option
== "--boost-root" )
2508 fs::path
p( argv
[ ++i
] );
2510 if( is_boost_root( p
) )
2512 fs::current_path( p
);
2517 std::cerr
<< "'" << p
.string() << "': not a valid Boost root.\n";
2523 std::cerr
<< "'" << option
<< "': missing argument.\n";
2529 if( !root_set
&& !find_boost_root() )
2531 char const * env_root
= std::getenv( "BOOST_ROOT" );
2533 if( env_root
&& is_boost_root( env_root
) )
2535 fs::current_path( env_root
);
2539 std::cerr
<< "boostdep: Could not find Boost root.\n";
2548 catch( fs::filesystem_error
const & x
)
2550 std::cerr
<< x
.what() << std::endl
;
2554 bool secondary
= false;
2555 bool track_sources
= false;
2556 bool track_tests
= false;
2558 std::string html_title
= "Boost Dependency Report";
2559 std::string html_footer
;
2560 std::string html_stylesheet
;
2561 std::string html_prefix
;
2563 std::ostringstream captured_output
;
2564 teebuf
tsb( std::cout
.rdbuf(), captured_output
.rdbuf() );
2566 save_cout_rdbuf scrdb
;
2568 for( int i
= 1; i
< argc
; ++i
)
2570 std::string option
= argv
[ i
];
2572 if( option
== "--boost-root" )
2576 else if( option
== "--list-modules" )
2580 else if( option
== "--list-buildable" )
2584 else if( option
== "--title" || option
== "--html-title" )
2588 html_title
= argv
[ ++i
];
2591 else if( option
== "--footer" || option
== "--html-footer" )
2595 html_footer
= argv
[ ++i
];
2598 else if( option
== "--html-stylesheet" )
2602 html_stylesheet
= argv
[ ++i
];
2605 else if( option
== "--html-prefix" )
2609 html_prefix
= argv
[ ++i
];
2612 else if( option
== "--html" )
2617 output_html_header( html_title
, html_stylesheet
, html_prefix
);
2620 else if( option
== "--track-sources" )
2622 track_sources
= true;
2624 else if( option
== "--no-track-sources" )
2626 track_sources
= false;
2628 else if( option
== "--track-tests" )
2632 else if( option
== "--no-track-tests" )
2634 track_tests
= false;
2636 else if( option
== "--primary" )
2640 output_module_primary_report( argv
[ ++i
], html
, track_sources
, track_tests
);
2643 else if( option
== "--secondary" )
2647 enable_secondary( secondary
, track_sources
, track_tests
);
2648 output_module_secondary_report( argv
[ ++i
], html
);
2651 else if( option
== "--reverse" )
2655 enable_secondary( secondary
, track_sources
, track_tests
);
2656 output_module_reverse_report( argv
[ ++i
], html
);
2659 else if( option
== "--header" )
2663 enable_secondary( secondary
, track_sources
, track_tests
);
2664 output_header_report( argv
[ ++i
], html
);
2667 else if( option
== "--subset" )
2671 enable_secondary( secondary
, track_sources
, track_tests
);
2672 output_module_subset_report( argv
[ ++i
], track_sources
, track_tests
, html
);
2675 else if( option
== "--test" )
2679 output_module_test_report( argv
[ ++i
] );
2682 else if( option
== "--cmake" )
2686 output_module_cmake_report( argv
[ ++i
] );
2689 else if( option
== "--module-levels" )
2691 enable_secondary( secondary
, track_sources
, track_tests
);
2692 output_module_level_report( html
);
2694 else if( option
== "--module-overview" )
2696 enable_secondary( secondary
, track_sources
, track_tests
);
2697 output_module_overview_report( html
);
2699 else if( option
== "--module-weights" )
2701 enable_secondary( secondary
, track_sources
, track_tests
);
2702 output_module_weight_report( html
);
2704 else if( option
== "--list-dependencies" )
2706 enable_secondary( secondary
, track_sources
, track_tests
);
2707 list_dependencies();
2709 else if( option
== "--list-exceptions" )
2713 else if( option
== "--list-missing-headers" )
2715 list_missing_headers();
2717 else if( option
== "--pkgconfig" )
2721 std::string module
= argv
[ ++i
];
2722 std::string version
= argv
[ ++i
];
2726 output_pkgconfig( module
, version
, argc
- i
, argv
+ i
);
2730 std::cerr
<< "'" << option
<< "': missing module or version.\n";
2735 else if( option
== "--subset-for" )
2739 std::string module
= argv
[ ++i
];
2741 enable_secondary( secondary
, track_sources
, track_tests
);
2743 std::set
<std::string
> headers
;
2744 add_module_headers( module
, headers
);
2746 output_directory_subset_report( module
, headers
, html
);
2750 std::cerr
<< "'" << option
<< "': missing argument.\n";
2755 else if( option
== "--list-buildable-dependencies" )
2757 enable_secondary( secondary
, true, false );
2758 list_buildable_dependencies();
2760 else if( option
== "--capture-output" )
2762 std::cout
.rdbuf( &tsb
);
2764 else if( option
== "--compare-output" )
2768 std::string fn
= argv
[ ++i
];
2769 std::fstream
is( fn
.c_str() );
2773 std::cerr
<< option
<< " '" << fn
<< "': could not open file.\n";
2777 std::istreambuf_iterator
<char> first( is
), last
;
2778 std::string
fc( first
, last
);
2780 if( fc
!= captured_output
.str() )
2782 std::cerr
<< option
<< " '" << fn
<< "': output does not match; expected output:\n---\n" << fc
<< "---\n";
2786 std::cerr
<< option
<< " '" << fn
<< "': output matches.\n";
2787 captured_output
.str( "" );
2791 std::cerr
<< "'" << option
<< "': missing argument.\n";
2795 else if( s_modules
.count( option
) )
2797 output_module_primary_report( option
, html
, track_sources
, track_tests
);
2799 else if( s_header_map
.count( option
) )
2801 enable_secondary( secondary
, track_sources
, track_tests
);
2802 output_header_report( option
, html
);
2806 std::cerr
<< "'" << option
<< "': not an option, module or header.\n";
2812 output_html_footer( html_footer
);