2 // boostdep - a tool to generate Boost dependency reports
4 // Copyright 2014-2020 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>
27 namespace fs
= boost::filesystem
;
30 static std::map
< std::string
, std::string
> s_header_map
;
33 static std::map
< std::string
, std::set
<std::string
> > s_module_headers
;
35 static std::set
< std::string
> s_modules
;
37 static void scan_module_headers( fs::path
const & path
)
41 std::string module
= path
.generic_string().substr( 5 ); // strip "libs/"
43 std::replace( module
.begin(), module
.end(), '/', '~' );
45 s_modules
.insert( module
);
47 fs::path dir
= path
/ "include";
48 size_t n
= dir
.generic_string().size();
50 fs::recursive_directory_iterator
it( dir
), last
;
52 for( ; it
!= last
; ++it
)
54 if( it
->status().type() == fs::directory_file
)
59 std::string p2
= it
->path().generic_string();
60 p2
= p2
.substr( n
+1 );
62 s_header_map
[ p2
] = module
;
63 s_module_headers
[ module
].insert( p2
);
66 catch( fs::filesystem_error
const & x
)
68 std::cout
<< x
.what() << std::endl
;
72 static void scan_submodules( fs::path
const & path
)
74 fs::directory_iterator
it( path
), last
;
76 for( ; it
!= last
; ++it
)
78 fs::directory_entry
const & e
= *it
;
80 if( e
.status().type() != fs::directory_file
)
85 fs::path path
= e
.path();
87 if( fs::exists( path
/ "include" ) )
89 scan_module_headers( path
);
92 if( fs::exists( path
/ "sublibs" ) )
94 scan_submodules( path
);
99 static void build_header_map()
101 scan_submodules( "libs" );
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
)
108 while( std::getline( is
, line
) )
110 while( !line
.empty() && ( line
[0] == ' ' || line
[0] == '\t' ) )
115 if( line
.empty() || line
[0] != '#' ) continue;
119 while( !line
.empty() && ( line
[0] == ' ' || line
[0] == '\t' ) )
124 if( line
.substr( 0, 7 ) != "include" ) continue;
128 while( !line
.empty() && ( line
[0] == ' ' || line
[0] == '\t' ) )
133 if( line
.size() < 2 ) continue;
137 if( ch
!= '<' && ch
!= '"' ) continue;
146 std::string::size_type k
= line
.find_first_of( ch
);
148 if( k
!= std::string::npos
)
153 std::map
< std::string
, std::string
>::const_iterator i
= s_header_map
.find( line
);
155 if( i
!= s_header_map
.end() )
157 deps
[ i
->second
].insert( line
);
158 from
[ line
].insert( header
);
160 else if( line
.substr( 0, 6 ) == "boost/" )
162 deps
[ "(unknown)" ].insert( line
);
163 from
[ line
].insert( header
);
168 struct module_primary_actions
170 virtual void heading( std::string
const & module
) = 0;
172 virtual void module_start( std::string
const & module
) = 0;
173 virtual void module_end( std::string
const & module
) = 0;
175 virtual void header_start( std::string
const & header
) = 0;
176 virtual void header_end( std::string
const & header
) = 0;
178 virtual void from_header( std::string
const & header
) = 0;
181 static fs::path
module_include_path( std::string module
)
183 std::replace( module
.begin(), module
.end(), '~', '/' );
184 return fs::path( "libs" ) / module
/ "include";
187 static fs::path
module_source_path( std::string module
)
189 std::replace( module
.begin(), module
.end(), '~', '/' );
190 return fs::path( "libs" ) / module
/ "src";
193 static fs::path
module_build_path( std::string module
)
195 std::replace( module
.begin(), module
.end(), '~', '/' );
196 return fs::path( "libs" ) / module
/ "build";
199 static fs::path
module_test_path( std::string module
)
201 std::replace( module
.begin(), module
.end(), '~', '/' );
202 return fs::path( "libs" ) / module
/ "test";
205 static void scan_module_path( fs::path
const & dir
, bool remove_prefix
, std::map
< std::string
, std::set
< std::string
> > & deps
, std::map
< std::string
, std::set
< std::string
> > & from
)
207 size_t n
= dir
.generic_string().size();
209 if( fs::exists( dir
) )
211 fs::recursive_directory_iterator
it( dir
), last
;
213 for( ; it
!= last
; ++it
)
215 if( it
->status().type() == fs::directory_file
)
220 std::string header
= it
->path().generic_string();
224 header
= header
.substr( n
+1 );
227 fs::ifstream
is( it
->path() );
229 scan_header_dependencies( header
, is
, deps
, from
);
234 static void scan_module_dependencies( std::string
const & module
, module_primary_actions
& actions
, bool track_sources
, bool track_tests
, bool include_self
)
236 // module -> [ header, header... ]
237 std::map
< std::string
, std::set
< std::string
> > deps
;
239 // header -> included from [ header, header... ]
240 std::map
< std::string
, std::set
< std::string
> > from
;
242 scan_module_path( module_include_path( module
), true, deps
, from
);
246 scan_module_path( module_source_path( module
), false, deps
, from
);
251 scan_module_path( module_test_path( module
), false, deps
, from
);
254 actions
.heading( module
);
256 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= deps
.begin(); i
!= deps
.end(); ++i
)
258 if( i
->first
== module
&& !include_self
) continue;
260 actions
.module_start( i
->first
);
262 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
264 actions
.header_start( *j
);
266 std::set
< std::string
> const & f
= from
[ *j
];
268 for( std::set
< std::string
>::const_iterator k
= f
.begin(); k
!= f
.end(); ++k
)
270 actions
.from_header( *k
);
273 actions
.header_end( *j
);
276 actions
.module_end( i
->first
);
280 // module depends on [ module, module... ]
281 static std::map
< std::string
, std::set
< std::string
> > s_module_deps
;
283 // header is included by [header, header...]
284 static std::map
< std::string
, std::set
< std::string
> > s_header_deps
;
286 // [ module, module... ] depend on module
287 static std::map
< std::string
, std::set
< std::string
> > s_reverse_deps
;
289 // header includes [header, header...]
290 static std::map
< std::string
, std::set
< std::string
> > s_header_includes
;
292 struct build_mdmap_actions
: public module_primary_actions
295 std::string module2_
;
298 void heading( std::string
const & module
)
303 void module_start( std::string
const & module
)
305 if( module
!= module_
)
307 s_module_deps
[ module_
].insert( module
);
308 s_reverse_deps
[ module
].insert( module_
);
314 void module_end( std::string
const & /*module*/ )
318 void header_start( std::string
const & header
)
323 void header_end( std::string
const & /*header*/ )
327 void from_header( std::string
const & header
)
329 if( module_
!= module2_
)
331 s_header_deps
[ header_
].insert( header
);
334 s_header_includes
[ header
].insert( header_
);
338 static void build_module_dependency_map( bool track_sources
, bool track_tests
)
340 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
342 build_mdmap_actions actions
;
343 scan_module_dependencies( *i
, actions
, track_sources
, track_tests
, true );
347 static void output_module_primary_report( std::string
const & module
, module_primary_actions
& actions
, bool track_sources
, bool track_tests
)
351 scan_module_dependencies( module
, actions
, track_sources
, track_tests
, false );
353 catch( fs::filesystem_error
const & x
)
355 std::cout
<< x
.what() << std::endl
;
359 struct module_secondary_actions
361 virtual void heading( std::string
const & module
) = 0;
363 virtual void module_start( std::string
const & module
) = 0;
364 virtual void module_end( std::string
const & module
) = 0;
366 virtual void module_adds( std::string
const & module
) = 0;
369 static void exclude( std::set
< std::string
> & x
, std::set
< std::string
> const & y
)
371 for( std::set
< std::string
>::const_iterator i
= y
.begin(); i
!= y
.end(); ++i
)
377 static void output_module_secondary_report( std::string
const & module
, std::set
< std::string
> deps
, module_secondary_actions
& actions
)
379 actions
.heading( module
);
381 deps
.insert( module
);
383 // build transitive closure
387 std::set
< std::string
> deps2( deps
);
389 for( std::set
< std::string
>::iterator i
= deps
.begin(); i
!= deps
.end(); ++i
)
391 std::set
< std::string
> deps3
= s_module_deps
[ *i
];
393 exclude( deps3
, deps
);
400 actions
.module_start( *i
);
402 for( std::set
< std::string
>::iterator j
= deps3
.begin(); j
!= deps3
.end(); ++j
)
404 actions
.module_adds( *j
);
407 actions
.module_end( *i
);
409 deps2
.insert( deps3
.begin(), deps3
.end() );
423 static void output_module_secondary_report( std::string
const & module
, module_secondary_actions
& actions
)
425 output_module_secondary_report( module
, s_module_deps
[ module
], actions
);
428 struct header_inclusion_actions
430 virtual void heading( std::string
const & header
, std::string
const & module
) = 0;
432 virtual void module_start( std::string
const & module
) = 0;
433 virtual void module_end( std::string
const & module
) = 0;
435 virtual void header( std::string
const & header
) = 0;
438 static std::string
module_for_header( std::string header
)
441 std::map
<std::string
, std::string
>::const_iterator i
= s_header_map
.find( header
);
443 if( i
!= s_header_map
.end() )
449 if( header
.substr( 0, 5 ) == "libs/" )
451 header
= header
.substr( 5 );
453 else if( header
.substr( 0, 5 ) == "test/" )
455 header
= header
.substr( 5 );
459 return std::string();
462 for( std::set
<std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
464 std::string module
= *i
;
465 std::replace( module
.begin(), module
.end(), '~', '/' );
467 if( header
.substr( 0, module
.size() + 1 ) == module
+ '/' )
473 return std::string();
476 static void output_header_inclusion_report( std::string
const & header
, header_inclusion_actions
& actions
)
478 std::string module
= s_header_map
[ header
];
480 actions
.heading( header
, module
);
482 std::set
< std::string
> from
= s_header_deps
[ header
];
484 // classify 'from' dependencies by module
486 // module -> [header, header...]
487 std::map
< std::string
, std::set
< std::string
> > from2
;
489 for( std::set
< std::string
>::iterator i
= from
.begin(); i
!= from
.end(); ++i
)
491 from2
[ module_for_header( *i
) ].insert( *i
);
494 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= from2
.begin(); i
!= from2
.end(); ++i
)
496 actions
.module_start( i
->first
);
498 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
500 actions
.header( *j
);
503 actions
.module_end( i
->first
);
507 // output_module_primary_report
509 struct module_primary_txt_actions
: public module_primary_actions
511 void heading( std::string
const & module
)
513 std::cout
<< "Primary dependencies for " << module
<< ":\n\n";
516 void module_start( std::string
const & module
)
518 std::cout
<< module
<< ":\n";
521 void module_end( std::string
const & /*module*/ )
526 void header_start( std::string
const & header
)
528 std::cout
<< " <" << header
<< ">\n";
531 void header_end( std::string
const & /*header*/ )
535 void from_header( std::string
const & header
)
537 std::cout
<< " from <" << header
<< ">\n";
541 struct module_primary_html_actions
: public module_primary_actions
543 void heading( std::string
const & module
)
545 std::cout
<< "\n\n<h1 id=\"primary-dependencies\">Primary dependencies for <em>" << module
<< "</em></h1>\n";
548 void module_start( std::string
const & module
)
550 std::cout
<< " <h2 id=\"" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2>\n";
553 void module_end( std::string
const & /*module*/ )
557 void header_start( std::string
const & header
)
559 std::cout
<< " <h3><code><" << header
<< "></code></h3><ul>\n";
562 void header_end( std::string
const & /*header*/ )
564 std::cout
<< " </ul>\n";
567 void from_header( std::string
const & header
)
569 std::cout
<< " <li>from <code><" << header
<< "></code></li>\n";
573 static void output_module_primary_report( std::string
const & module
, bool html
, bool track_sources
, bool track_tests
)
577 module_primary_html_actions actions
;
578 output_module_primary_report( module
, actions
, track_sources
, track_tests
);
582 module_primary_txt_actions actions
;
583 output_module_primary_report( module
, actions
, track_sources
, track_tests
);
587 // output_module_secondary_report
589 struct module_secondary_txt_actions
: public module_secondary_actions
591 void heading( std::string
const & module
)
593 std::cout
<< "Secondary dependencies for " << module
<< ":\n\n";
596 void module_start( std::string
const & module
)
598 std::cout
<< module
<< ":\n";
601 void module_end( std::string
const & /*module*/ )
606 void module_adds( std::string
const & module
)
608 std::cout
<< " adds " << module
<< "\n";
612 struct module_secondary_html_actions
: public module_secondary_actions
616 void heading( std::string
const & module
)
618 std::cout
<< "\n\n<h1 id=\"secondary-dependencies\">Secondary dependencies for <em>" << module
<< "</em></h1>\n";
621 void module_start( std::string
const & module
)
623 std::cout
<< " <h2><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
627 void module_end( std::string
const & /*module*/ )
629 std::cout
<< " </ul>\n";
632 void module_adds( std::string
const & module
)
634 std::cout
<< " <li><a href=\"" << m2_
<< ".html#" << module
<< "\">adds <em>" << module
<< "</em></a></li>\n";
638 static void output_module_secondary_report( std::string
const & module
, bool html
)
642 module_secondary_html_actions actions
;
643 output_module_secondary_report( module
, actions
);
647 module_secondary_txt_actions actions
;
648 output_module_secondary_report( module
, actions
);
652 // output_header_report
654 struct header_inclusion_txt_actions
: public header_inclusion_actions
656 void heading( std::string
const & header
, std::string
const & module
)
658 std::cout
<< "Inclusion report for <" << header
<< "> (in module " << module
<< "):\n\n";
661 void module_start( std::string
const & module
)
663 std::cout
<< " from " << module
<< ":\n";
666 void module_end( std::string
const & /*module*/ )
671 void header( std::string
const & header
)
673 std::cout
<< " <" << header
<< ">\n";
677 struct header_inclusion_html_actions
: public header_inclusion_actions
679 void heading( std::string
const & header
, std::string
const & module
)
681 std::cout
<< "<h1>Inclusion report for <code><" << header
<< "></code> (in module <em>" << module
<< "</em>)</h1>\n";
684 void module_start( std::string
const & module
)
686 std::cout
<< " <h2>From <a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
689 void module_end( std::string
const & /*module*/ )
691 std::cout
<< " </ul>\n";
694 void header( std::string
const & header
)
696 std::cout
<< " <li><code><" << header
<< "></code></li>\n";
700 static void output_header_report( std::string
const & header
, bool html
)
704 header_inclusion_html_actions actions
;
705 output_header_inclusion_report( header
, actions
);
709 header_inclusion_txt_actions actions
;
710 output_header_inclusion_report( header
, actions
);
714 // output_module_reverse_report
716 struct module_reverse_actions
718 virtual void heading( std::string
const & module
) = 0;
720 virtual void module_start( std::string
const & module
) = 0;
721 virtual void module_end( std::string
const & module
) = 0;
723 virtual void header_start( std::string
const & header
) = 0;
724 virtual void header_end( std::string
const & header
) = 0;
726 virtual void from_header( std::string
const & header
) = 0;
729 static void output_module_reverse_report( std::string
const & module
, module_reverse_actions
& actions
)
731 actions
.heading( module
);
733 std::set
< std::string
> const from
= s_reverse_deps
[ module
];
735 for( std::set
< std::string
>::const_iterator i
= from
.begin(); i
!= from
.end(); ++i
)
737 actions
.module_start( *i
);
739 for( std::map
< std::string
, std::set
< std::string
> >::iterator j
= s_header_deps
.begin(); j
!= s_header_deps
.end(); ++j
)
741 if( module_for_header( j
->first
) == module
)
743 bool header_started
= false;
745 for( std::set
< std::string
>::iterator k
= j
->second
.begin(); k
!= j
->second
.end(); ++k
)
747 if( module_for_header( *k
) == *i
)
749 if( !header_started
)
751 actions
.header_start( j
->first
);
753 header_started
= true;
756 actions
.from_header( *k
);
762 actions
.header_end( j
->first
);
767 actions
.module_end( *i
);
771 struct module_reverse_txt_actions
: public module_reverse_actions
773 void heading( std::string
const & module
)
775 std::cout
<< "Reverse dependencies for " << module
<< ":\n\n";
778 void module_start( std::string
const & module
)
780 std::cout
<< module
<< ":\n";
783 void module_end( std::string
const & /*module*/ )
788 void header_start( std::string
const & header
)
790 std::cout
<< " <" << header
<< ">\n";
793 void header_end( std::string
const & /*header*/ )
797 void from_header( std::string
const & header
)
799 std::cout
<< " from <" << header
<< ">\n";
803 struct module_reverse_html_actions
: public module_reverse_actions
805 void heading( std::string
const & module
)
807 std::cout
<< "\n\n<h1 id=\"reverse-dependencies\">Reverse dependencies for <em>" << module
<< "</em></h1>\n";
810 void module_start( std::string
const & module
)
812 std::cout
<< " <h2 id=\"reverse-" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2>\n";
815 void module_end( std::string
const & /*module*/ )
819 void header_start( std::string
const & header
)
821 std::cout
<< " <h3><code><" << header
<< "></code></h3><ul>\n";
824 void header_end( std::string
const & /*header*/ )
826 std::cout
<< " </ul>\n";
829 void from_header( std::string
const & header
)
831 std::cout
<< " <li>from <code><" << header
<< "></code></li>\n";
835 static void output_module_reverse_report( std::string
const & module
, bool html
)
839 module_reverse_html_actions actions
;
840 output_module_reverse_report( module
, actions
);
844 module_reverse_txt_actions actions
;
845 output_module_reverse_report( module
, actions
);
849 // module_level_report
851 int const unknown_level
= INT_MAX
/ 2;
853 struct module_level_actions
855 virtual void begin() = 0;
856 virtual void end() = 0;
858 virtual void level_start( int level
) = 0;
859 virtual void level_end( int level
) = 0;
861 virtual void module_start( std::string
const & module
) = 0;
862 virtual void module_end( std::string
const & module
) = 0;
864 virtual void module2( std::string
const & module
, int level
) = 0;
867 static void output_module_level_report( module_level_actions
& actions
)
869 // build module level map
871 std::map
< std::string
, int > level_map
;
873 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
875 if( s_module_deps
[ *i
].empty() )
878 // std::cerr << *i << ": " << 0 << std::endl;
882 level_map
[ *i
] = unknown_level
;
886 // build transitive closure to see through cycles
888 std::map
< std::string
, std::set
< std::string
> > deps2
= s_module_deps
;
897 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= deps2
.begin(); i
!= deps2
.end(); ++i
)
899 std::set
< std::string
> tmp
= i
->second
;
901 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
903 std::set
< std::string
> tmp2
= deps2
[ *j
];
904 tmp
.insert( tmp2
.begin(), tmp2
.end() );
907 if( tmp
.size() != i
->second
.size() )
917 // compute acyclic levels
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 // i->first depends on i->second
925 if( level_map
[ i
->first
] >= unknown_level
)
929 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
931 level
= std::max( level
, level_map
[ *j
] + 1 );
936 level_map
[ i
->first
] = level
;
937 // std::cerr << i->first << ": " << level << std::endl;
943 // min_level_map[ M ] == L means the level is unknown, but at least L
944 std::map
< std::string
, int > min_level_map
;
946 // initialize min_level_map for acyclic dependencies
948 for( std::map
< std::string
, int >::iterator i
= level_map
.begin(); i
!= level_map
.end(); ++i
)
950 if( i
->second
< unknown_level
)
952 min_level_map
[ i
->first
] = i
->second
;
956 // compute levels for cyclic modules
958 for( int k
= 1, n
= s_modules
.size(); k
< n
; ++k
)
960 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= s_module_deps
.begin(); i
!= s_module_deps
.end(); ++i
)
962 if( level_map
[ i
->first
] >= unknown_level
)
966 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
968 int jl
= level_map
[ *j
];
970 if( jl
< unknown_level
)
972 level
= std::max( level
, jl
+ 1 );
976 int ml
= min_level_map
[ *j
];
978 if( deps2
[ *j
].count( i
->first
) == 0 )
980 // *j does not depend on i->first, so
981 // the level of i->first is at least
982 // 1 + the minimum level of *j
987 level
= std::max( level
, ml
);
991 min_level_map
[ i
->first
] = level
;
998 std::map
< int, std::set
< std::string
> > reverse_level_map
;
1000 for( std::map
< std::string
, int >::iterator i
= level_map
.begin(); i
!= level_map
.end(); ++i
)
1002 int level
= i
->second
;
1004 if( level
>= unknown_level
)
1006 int min_level
= min_level_map
[ i
->first
];
1008 if( min_level
!= 0 )
1014 reverse_level_map
[ level
].insert( i
->first
);
1021 for( std::map
< int, std::set
< std::string
> >::iterator i
= reverse_level_map
.begin(); i
!= reverse_level_map
.end(); ++i
)
1023 actions
.level_start( i
->first
);
1025 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1027 actions
.module_start( *j
);
1029 std::set
< std::string
> mdeps
= s_module_deps
[ *j
];
1031 for( std::set
< std::string
>::iterator k
= mdeps
.begin(); k
!= mdeps
.end(); ++k
)
1033 int level
= level_map
[ *k
];
1035 if( level
>= unknown_level
)
1037 int min_level
= min_level_map
[ *k
];
1039 if( min_level
!= 0 )
1045 actions
.module2( *k
, level
);
1048 actions
.module_end( *j
);
1051 actions
.level_end( i
->first
);
1057 struct module_level_txt_actions
: public module_level_actions
1063 std::cout
<< "Module Levels:\n\n";
1070 void level_start( int level
)
1072 if( level
>= unknown_level
)
1074 std::cout
<< "Level (undetermined):\n";
1078 std::cout
<< "Level " << level
<< ":\n";
1084 void level_end( int /*level*/ )
1089 void module_start( std::string
const & module
)
1091 std::cout
<< " " << module
;
1099 void module_end( std::string
const & /*module*/ )
1104 void module2( std::string
const & module
, int level
)
1106 std::cout
<< " " << module
<< "(";
1108 if( level
>= unknown_level
)
1121 struct module_level_html_actions
: public module_level_actions
1127 std::cout
<< "<div id='module-levels'><h1>Module Levels</h1>\n";
1132 std::cout
<< "</div>\n";
1135 void level_start( int level
)
1137 if( level
>= unknown_level
)
1139 std::cout
<< " <h2>Level <em>undetermined</em></h2>\n";
1143 std::cout
<< " <h2 id='level:" << level
<< "'>Level " << level
<< "</h2>\n";
1149 void level_end( int /*level*/ )
1153 void module_start( std::string
const & module
)
1155 std::cout
<< " <h3 id='" << module
<< "'><a href=\"" << module
<< ".html\">" << module
<< "</a></h3><p class='primary-list'>";
1158 void module_end( std::string
const & /*module*/ )
1160 std::cout
<< "</p>\n";
1163 void module2( std::string
const & module
, int level
)
1167 bool important
= level
< unknown_level
&& level
> 1 && level
>= level_
- 1;
1171 std::cout
<< "<strong>";
1174 std::cout
<< module
;
1176 if( level
< unknown_level
)
1178 std::cout
<< "<sup>" << level
<< "</sup>";
1183 std::cout
<< "</strong>";
1188 static void output_module_level_report( bool html
)
1192 module_level_html_actions actions
;
1193 output_module_level_report( actions
);
1197 module_level_txt_actions actions
;
1198 output_module_level_report( actions
);
1202 // module_overview_report
1204 struct module_overview_actions
1206 virtual void begin() = 0;
1207 virtual void end() = 0;
1209 virtual void module_start( std::string
const & module
) = 0;
1210 virtual void module_end( std::string
const & module
) = 0;
1212 virtual void module2( std::string
const & module
) = 0;
1215 static void output_module_overview_report( module_overview_actions
& actions
)
1219 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1221 actions
.module_start( *i
);
1223 std::set
< std::string
> const mdeps
= s_module_deps
[ *i
];
1225 for( std::set
< std::string
>::const_iterator j
= mdeps
.begin(); j
!= mdeps
.end(); ++j
)
1227 actions
.module2( *j
);
1230 actions
.module_end( *i
);
1236 struct module_overview_txt_actions
: public module_overview_actions
1242 std::cout
<< "Module Overview:\n\n";
1249 void module_start( std::string
const & module
)
1251 std::cout
<< module
;
1255 void module_end( std::string
const & /*module*/ )
1260 void module2( std::string
const & module
)
1268 std::cout
<< " " << module
;
1272 struct module_overview_html_actions
: public module_overview_actions
1276 std::cout
<< "<div id='module-overview'><h1>Module Overview</h1>\n";
1281 std::cout
<< "</div>\n";
1284 void module_start( std::string
const & module
)
1286 std::cout
<< " <h2 id='" << module
<< "'><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><p class='primary-list'>";
1289 void module_end( std::string
const & /*module*/ )
1291 std::cout
<< "</p>\n";
1294 void module2( std::string
const & module
)
1296 std::cout
<< " " << module
;
1300 static void output_module_overview_report( bool html
)
1304 module_overview_html_actions actions
;
1305 output_module_overview_report( actions
);
1309 module_overview_txt_actions actions
;
1310 output_module_overview_report( actions
);
1314 // list_dependencies
1316 struct list_dependencies_actions
: public module_overview_actions
1326 void module_start( std::string
const & module
)
1328 std::cout
<< module
<< " ->";
1331 void module_end( std::string
const & /*module*/ )
1336 void module2( std::string
const & module
)
1338 if( module
!= "(unknown)" )
1340 std::cout
<< " " << module
;
1345 static void list_dependencies()
1347 list_dependencies_actions actions
;
1348 output_module_overview_report( actions
);
1353 static void output_html_header( std::string
const & title
, std::string
const & stylesheet
, std::string
const & prefix
)
1355 std::cout
<< "<html>\n";
1356 std::cout
<< "<head>\n";
1357 std::cout
<< "<title>" << title
<< "</title>\n";
1359 if( !stylesheet
.empty() )
1361 std::cout
<< "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet
<< "\" />\n";
1364 std::cout
<< "</head>\n";
1365 std::cout
<< "<body>\n";
1367 if( !prefix
.empty() )
1369 std::cout
<< prefix
<< std::endl
;
1373 static void output_html_footer( std::string
const & footer
)
1375 std::cout
<< "<hr />\n";
1376 std::cout
<< "<p class=\"footer\">" << footer
<< "</p>\n";
1377 std::cout
<< "</body>\n";
1378 std::cout
<< "</html>\n";
1381 static void enable_secondary( bool & secondary
, bool track_sources
, bool track_tests
)
1387 build_module_dependency_map( track_sources
, track_tests
);
1389 catch( fs::filesystem_error
const & x
)
1391 std::cout
<< x
.what() << std::endl
;
1398 static void list_modules()
1400 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1402 std::cout
<< *i
<< "\n";
1406 static void list_buildable()
1408 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1410 if( fs::exists( module_build_path( *i
) ) && fs::exists( module_source_path( *i
) ) )
1412 std::cout
<< *i
<< "\n";
1417 // module_weight_report
1419 struct module_weight_actions
1421 virtual void begin() = 0;
1422 virtual void end() = 0;
1424 virtual void weight_start( int weight
) = 0;
1425 virtual void weight_end( int weight
) = 0;
1427 virtual void module_start( std::string
const & module
) = 0;
1428 virtual void module_end( std::string
const & module
) = 0;
1430 virtual void module_primary_start() = 0;
1431 virtual void module_primary( std::string
const & module
, int weight
) = 0;
1432 virtual void module_primary_end() = 0;
1434 virtual void module_secondary_start() = 0;
1435 virtual void module_secondary( std::string
const & module
, int weight
) = 0;
1436 virtual void module_secondary_end() = 0;
1439 static void output_module_weight_report( module_weight_actions
& actions
)
1441 // gather secondary dependencies
1443 struct build_secondary_deps
: public module_secondary_actions
1445 std::map
< std::string
, std::set
< std::string
> > * pm_
;
1447 build_secondary_deps( std::map
< std::string
, std::set
< std::string
> > * pm
): pm_( pm
)
1451 std::string module_
;
1453 void heading( std::string
const & module
)
1458 void module_start( std::string
const & /*module*/ )
1462 void module_end( std::string
const & /*module*/ )
1466 void module_adds( std::string
const & module
)
1468 (*pm_
)[ module_
].insert( module
);
1472 std::map
< std::string
, std::set
< std::string
> > secondary_deps
;
1474 build_secondary_deps
bsd( &secondary_deps
);
1476 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1478 output_module_secondary_report( *i
, bsd
);
1483 std::map
< int, std::set
< std::string
> > modules_by_weight
;
1485 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1487 int w
= s_module_deps
[ *i
].size() + secondary_deps
[ *i
].size();
1488 modules_by_weight
[ w
].insert( *i
);
1495 for( std::map
< int, std::set
< std::string
> >::const_iterator i
= modules_by_weight
.begin(); i
!= modules_by_weight
.end(); ++i
)
1497 actions
.weight_start( i
->first
);
1499 for( std::set
< std::string
>::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1501 actions
.module_start( *j
);
1503 if( !s_module_deps
[ *j
].empty() )
1505 actions
.module_primary_start();
1507 for( std::set
< std::string
>::const_iterator k
= s_module_deps
[ *j
].begin(); k
!= s_module_deps
[ *j
].end(); ++k
)
1509 int w
= s_module_deps
[ *k
].size() + secondary_deps
[ *k
].size();
1510 actions
.module_primary( *k
, w
);
1513 actions
.module_primary_end();
1516 if( !secondary_deps
[ *j
].empty() )
1518 actions
.module_secondary_start();
1520 for( std::set
< std::string
>::const_iterator k
= secondary_deps
[ *j
].begin(); k
!= secondary_deps
[ *j
].end(); ++k
)
1522 int w
= s_module_deps
[ *k
].size() + secondary_deps
[ *k
].size();
1523 actions
.module_secondary( *k
, w
);
1526 actions
.module_secondary_end();
1529 actions
.module_end( *j
);
1532 actions
.weight_end( i
->first
);
1538 struct module_weight_txt_actions
: public module_weight_actions
1542 std::cout
<< "Module Weights:\n\n";
1549 void weight_start( int weight
)
1551 std::cout
<< "Weight " << weight
<< ":\n";
1554 void weight_end( int /*weight*/ )
1559 void module_start( std::string
const & module
)
1561 std::cout
<< " " << module
;
1564 void module_end( std::string
const & /*module*/ )
1569 void module_primary_start()
1574 void module_primary( std::string
const & module
, int weight
)
1576 std::cout
<< " " << module
<< "(" << weight
<< ")";
1579 void module_primary_end()
1583 void module_secondary_start()
1588 void module_secondary( std::string
const & module
, int /*weight*/ )
1590 std::cout
<< " " << module
;
1593 void module_secondary_end()
1598 struct module_weight_html_actions
: public module_weight_actions
1604 std::cout
<< "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
1609 std::cout
<< "</div>\n";
1612 void weight_start( int weight
)
1614 std::cout
<< " <h2 id='weight:" << weight
<< "'>Weight " << weight
<< "</h2>\n";
1618 void weight_end( int /*weight*/ )
1622 void module_start( std::string
const & module
)
1624 std::cout
<< " <h3 id='" << module
<< "'><a href=\"" << module
<< ".html\">" << module
<< "</a></h3>";
1627 void module_end( std::string
const & /*module*/ )
1632 void module_primary_start()
1634 std::cout
<< "<p class='primary-list'>";
1637 void module_primary( std::string
const & module
, int weight
)
1641 bool heavy
= weight
>= 0.8 * weight_
;
1645 std::cout
<< "<strong>";
1648 std::cout
<< module
<< "<sup>" << weight
<< "</sup>";
1652 std::cout
<< "</strong>";
1656 void module_primary_end()
1658 std::cout
<< "</p>";
1661 void module_secondary_start()
1663 std::cout
<< "<p class='secondary-list'>";
1666 void module_secondary( std::string
const & module
, int /*weight*/ )
1668 std::cout
<< " " << module
;
1671 void module_secondary_end()
1673 std::cout
<< "</p>";
1677 static void output_module_weight_report( bool html
)
1681 module_weight_html_actions actions
;
1682 output_module_weight_report( actions
);
1686 module_weight_txt_actions actions
;
1687 output_module_weight_report( actions
);
1691 // output_module_subset_report
1693 struct module_subset_actions
1695 virtual void heading( std::string
const & module
) = 0;
1697 virtual void module_start( std::string
const & module
) = 0;
1698 virtual void module_end( std::string
const & module
) = 0;
1700 virtual void from_path( std::vector
<std::string
> const & path
) = 0;
1703 static void add_module_headers( fs::path
const & dir
, std::set
<std::string
> & headers
)
1705 if( fs::exists( dir
) )
1707 fs::recursive_directory_iterator
it( dir
), last
;
1709 for( ; it
!= last
; ++it
)
1711 if( it
->status().type() == fs::directory_file
)
1716 headers
.insert( it
->path().generic_string() );
1721 static void output_module_subset_report_( std::string
const & module
, std::set
<std::string
> const & headers
, module_subset_actions
& actions
)
1723 // build header closure
1725 // header -> (header)*
1726 std::map
< std::string
, std::set
<std::string
> > inc2
;
1728 // (header, header) -> path
1729 std::map
< std::pair
<std::string
, std::string
>, std::vector
<std::string
> > paths
;
1731 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
1733 std::set
<std::string
> & s
= inc2
[ *i
];
1735 s
= s_header_includes
[ *i
];
1737 for( std::set
<std::string
>::const_iterator j
= s
.begin(); j
!= s
.end(); ++j
)
1739 std::vector
<std::string
> & v
= paths
[ std::make_pair( *i
, *j
) ];
1751 for( std::map
< std::string
, std::set
<std::string
> >::iterator i
= inc2
.begin(); i
!= inc2
.end(); ++i
)
1753 std::set
<std::string
> & s2
= i
->second
;
1755 for( std::set
<std::string
>::const_iterator j
= s2
.begin(); j
!= s2
.end(); ++j
)
1757 std::set
<std::string
> const & s
= s_header_includes
[ *j
];
1759 for( std::set
<std::string
>::const_iterator k
= s
.begin(); k
!= s
.end(); ++k
)
1761 if( s2
.count( *k
) == 0 )
1765 std::vector
<std::string
> const & v1
= paths
[ std::make_pair( i
->first
, *j
) ];
1766 std::vector
<std::string
> & v2
= paths
[ std::make_pair( i
->first
, *k
) ];
1780 // module -> header -> path [header -> header -> header]
1781 std::map
< std::string
, std::map
< std::string
, std::vector
<std::string
> > > subset
;
1783 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
1785 std::set
<std::string
> const & s
= inc2
[ *i
];
1787 for( std::set
<std::string
>::const_iterator j
= s
.begin(); j
!= s
.end(); ++j
)
1789 std::string
const & m
= s_header_map
[ *j
];
1791 if( m
.empty() ) continue;
1793 std::vector
<std::string
> const & path
= paths
[ std::make_pair( *i
, *j
) ];
1795 if( subset
.count( m
) == 0 || subset
[ m
].count( *i
) == 0 || subset
[ m
][ *i
].size() > path
.size() )
1797 subset
[ m
][ *i
] = path
;
1802 actions
.heading( module
);
1804 for( std::map
< std::string
, std::map
< std::string
, std::vector
<std::string
> > >::const_iterator i
= subset
.begin(); i
!= subset
.end(); ++i
)
1806 if( i
->first
== module
) continue;
1808 actions
.module_start( i
->first
);
1812 for( std::map
< std::string
, std::vector
<std::string
> >::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end() && k
< 4; ++j
, ++k
)
1814 actions
.from_path( j
->second
);
1817 actions
.module_end( i
->first
);
1821 static void output_module_subset_report( std::string
const & module
, bool track_sources
, bool track_tests
, module_subset_actions
& actions
)
1823 std::set
<std::string
> headers
= s_module_headers
[ module
];
1827 add_module_headers( module_source_path( module
), headers
);
1832 add_module_headers( module_test_path( module
), headers
);
1835 output_module_subset_report_( module
, headers
, actions
);
1838 struct module_subset_txt_actions
: public module_subset_actions
1840 void heading( std::string
const & module
)
1842 std::cout
<< "Subset dependencies for " << module
<< ":\n\n";
1845 void module_start( std::string
const & module
)
1847 std::cout
<< module
<< ":\n";
1850 void module_end( std::string
const & /*module*/ )
1855 void from_path( std::vector
<std::string
> const & path
)
1857 for( std::vector
<std::string
>::const_iterator i
= path
.begin(); i
!= path
.end(); ++i
)
1859 if( i
== path
.begin() )
1865 std::cout
<< " -> ";
1875 struct module_subset_html_actions
: public module_subset_actions
1877 void heading( std::string
const & module
)
1879 std::cout
<< "\n\n<h1 id=\"subset-dependencies\">Subset dependencies for <em>" << module
<< "</em></h1>\n";
1882 void module_start( std::string
const & module
)
1884 std::cout
<< " <h2 id=\"subset-" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
1887 void module_end( std::string
const & /*module*/ )
1889 std::cout
<< "</ul>\n";
1892 void from_path( std::vector
<std::string
> const & path
)
1894 std::cout
<< " <li>";
1896 for( std::vector
<std::string
>::const_iterator i
= path
.begin(); i
!= path
.end(); ++i
)
1898 if( i
!= path
.begin() )
1900 std::cout
<< " ⇢ ";
1903 std::cout
<< "<code>" << *i
<< "</code>";
1906 std::cout
<< "</li>\n";
1910 static void output_module_subset_report( std::string
const & module
, bool track_sources
, bool track_tests
, bool html
)
1914 module_subset_html_actions actions
;
1915 output_module_subset_report( module
, track_sources
, track_tests
, actions
);
1919 module_subset_txt_actions actions
;
1920 output_module_subset_report( module
, track_sources
, track_tests
, actions
);
1924 // --list-exceptions
1926 static void list_exceptions()
1930 for( std::map
< std::string
, std::set
<std::string
> >::const_iterator i
= s_module_headers
.begin(); i
!= s_module_headers
.end(); ++i
)
1932 std::string module
= i
->first
;
1934 std::replace( module
.begin(), module
.end(), '~', '/' );
1936 std::string
const prefix
= "boost/" + module
;
1937 size_t const n
= prefix
.size();
1939 for( std::set
< std::string
>::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1941 std::string
const & header
= *j
;
1943 if( header
.substr( 0, n
+1 ) != prefix
+ '/' && header
!= prefix
+ ".hpp" )
1947 std::cout
<< module
<< ":\n";
1951 std::cout
<< " " << header
<< '\n';
1959 struct module_test_primary_actions
: public module_primary_actions
1961 std::set
< std::string
> & m_
;
1963 module_test_primary_actions( std::set
< std::string
> & m
): m_( m
)
1967 void heading( std::string
const & module
)
1969 std::cout
<< "Test dependencies for " << module
<< ":\n\n";
1972 void module_start( std::string
const & module
)
1974 std::cout
<< module
<< "\n";
1975 m_
.insert( module
);
1978 void module_end( std::string
const & /*module*/ )
1982 void header_start( std::string
const & /*header*/ )
1986 void header_end( std::string
const & /*header*/ )
1990 void from_header( std::string
const & /*header*/ )
1995 struct module_test_secondary_actions
: public module_secondary_actions
1997 std::set
< std::string
> & m_
;
2000 module_test_secondary_actions( std::set
< std::string
> & m
): m_( m
)
2004 void heading( std::string
const & /*module*/ )
2008 void module_start( std::string
const & module
)
2013 void module_end( std::string
const & /*module*/ )
2017 void module_adds( std::string
const & module
)
2019 if( m_
.count( module
) == 0 )
2021 std::cout
<< module
<< " (from " << m2_
<< ")\n";
2022 m_
.insert( module
);
2027 static void output_module_test_report( std::string
const & module
)
2029 std::set
< std::string
> m
;
2031 module_test_primary_actions
a1( m
);
2032 output_module_primary_report( module
, a1
, true, true );
2036 bool secondary
= false;
2037 enable_secondary( secondary
, true, false );
2039 std::set
< std::string
> m2( m
);
2040 m2
.insert( module
);
2042 module_test_secondary_actions
a2( m2
);
2044 output_module_secondary_report( module
, m
, a2
);
2049 struct collect_primary_dependencies
: public module_primary_actions
2051 std::set
< std::string
> set_
;
2053 void heading( std::string
const & )
2057 void module_start( std::string
const & module
)
2059 if( module
== "(unknown)" ) return;
2061 set_
.insert( module
);
2064 void module_end( std::string
const & /*module*/ )
2068 void header_start( std::string
const & /*header*/ )
2072 void header_end( std::string
const & /*header*/ )
2076 void from_header( std::string
const & /*header*/ )
2081 static std::string
module_cmake_name( std::string module
)
2083 std::replace( module
.begin(), module
.end(), '~', '_' );
2087 static void output_module_cmake_report( std::string module
)
2091 "# Generated by `boostdep --cmake " << module
<< "`\n"
2092 "# Copyright 2020 Peter Dimov\n"
2093 "# Distributed under the Boost Software License, Version 1.0.\n"
2094 "# https://www.boost.org/LICENSE_1_0.txt\n"
2096 "cmake_minimum_required(VERSION 3.5...3.16)\n"
2100 std::replace( module
.begin(), module
.end(), '/', '~' );
2102 std::vector
<std::string
> sources
;
2103 bool has_c_sources
= false;
2105 fs::path srcpath
= module_source_path( module
);
2107 if( fs::exists( srcpath
) )
2109 fs::directory_iterator
it( srcpath
), last
;
2111 for( ; it
!= last
; ++it
)
2113 if( it
->status().type() != fs::regular_file
) continue;
2115 fs::path p
= it
->path();
2116 std::string ext
= p
.extension().string();
2118 if( ext
!= ".cpp" && ext
!= ".c" ) continue;
2120 std::string name
= p
.filename().string();
2122 sources
.push_back( name
);
2124 if( ext
== ".c" ) has_c_sources
= true;
2128 std::string
lm( module
);
2130 std::replace( lm
.begin(), lm
.end(), '~', '_' );
2134 "project(boost_" << lm
<< " VERSION \"${BOOST_SUPERPROJECT_VERSION}\" LANGUAGES" << ( has_c_sources
? " C": "" ) << " CXX)\n"
2138 collect_primary_dependencies a1
;
2139 output_module_primary_report( module
, a1
, false, false );
2141 if( !fs::exists( srcpath
) )
2143 // header-only library
2147 "add_library(boost_" << lm
<< " INTERFACE)\n"
2148 "add_library(Boost::" << lm
<< " ALIAS boost_" << lm
<< ")\n"
2150 "target_include_directories(boost_" << lm
<< " INTERFACE include)\n"
2154 if( !a1
.set_
.empty() )
2158 "target_link_libraries(boost_" << lm
<< "\n"
2162 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2164 std::cout
<< " Boost::" << module_cmake_name( *i
) << "\n";
2180 "add_library(boost_" << lm
<< "\n";
2182 for( std::vector
<std::string
>::iterator i
= sources
.begin(); i
!= sources
.end(); ++i
)
2184 std::cout
<< " src/" << *i
<< "\n";
2191 "add_library(Boost::" << lm
<< " ALIAS boost_" << lm
<< ")\n"
2193 "target_include_directories(boost_" << lm
<< " PUBLIC include)\n"
2197 collect_primary_dependencies a2
;
2198 output_module_primary_report( module
, a2
, true, false );
2200 if( !a1
.set_
.empty() || !a2
.set_
.empty() )
2204 "target_link_libraries(boost_" << lm
<< "\n"
2207 if( !a1
.set_
.empty() )
2214 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2216 a2
.set_
.erase( *i
);
2217 std::cout
<< " Boost::" << module_cmake_name( *i
) << "\n";
2221 if( !a2
.set_
.empty() )
2228 for( std::set
< std::string
>::const_iterator i
= a2
.set_
.begin(); i
!= a2
.set_
.end(); ++i
)
2230 std::cout
<< " Boost::" << module_cmake_name( *i
) << "\n";
2241 std::string
um( lm
);
2243 for( std::string::iterator i
= um
.begin(); i
!= um
.end(); ++i
)
2245 *i
= std::toupper( static_cast<unsigned char>( *i
) );
2250 "target_compile_definitions(boost_" << lm
<< "\n"
2251 " PUBLIC BOOST_" << um
<< "_NO_LIB\n"
2252 " PRIVATE BOOST_" << um
<< "_SOURCE\n"
2255 "if(BUILD_SHARED_LIBS)\n"
2256 " target_compile_definitions(boost_" << lm
<< " PUBLIC BOOST_" << um
<< "_DYN_LINK)\n"
2258 " target_compile_definitions(boost_" << lm
<< " PUBLIC BOOST_" << um
<< "_STATIC_LINK)\n"
2266 "if(BUILD_TESTING AND EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt\")\n"
2268 " add_subdirectory(test)\n"
2275 // --list-missing-headers
2277 struct missing_header_actions
: public module_primary_actions
2279 std::string module_
, module2_
;
2281 void heading( std::string
const & module
)
2286 void module_start( std::string
const & module
)
2291 void module_end( std::string
const & /*module*/ )
2295 void header_start( std::string
const & header
)
2297 if( module2_
== "(unknown)" )
2299 if( !module_
.empty() )
2301 std::cout
<< module_
<< ":\n";
2305 std::cout
<< " <" << header
<< ">\n";
2309 void header_end( std::string
const & /*header*/ )
2313 void from_header( std::string
const & header
)
2315 if( module2_
== "(unknown)" )
2317 std::cout
<< " from <" << header
<< ">\n";
2322 static void list_missing_headers( std::string
const & module
)
2324 missing_header_actions a
;
2325 output_module_primary_report( module
, a
, false, false );
2328 static void list_missing_headers()
2330 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
2332 list_missing_headers( *i
);
2338 struct primary_pkgconfig_actions
: public module_primary_actions
2340 std::string version_
;
2343 void heading( std::string
const & )
2347 void module_start( std::string
const & module
)
2349 if( module
== "(unknown)" ) return;
2351 std::string
m2( module
);
2352 std::replace( m2
.begin(), m2
.end(), '~', '_' );
2354 if( !list_
.empty() )
2359 list_
+= "boost_" + m2
+ " = " + version_
;
2362 void module_end( std::string
const & )
2366 void header_start( std::string
const & )
2370 void header_end( std::string
const & )
2374 void from_header( std::string
const & )
2379 static void output_requires( std::string
const & section
, std::string
const & version
, std::set
< std::string
> const & s
)
2383 for( std::set
< std::string
>::const_iterator i
= s
.begin(); i
!= s
.end(); ++i
)
2387 std::cout
<< section
<< ": ";
2395 std::string
m2( *i
);
2396 std::replace( m2
.begin(), m2
.end(), '~', '_' );
2398 std::cout
<< "boost_" << m2
<< " = " << version
;
2402 static void output_pkgconfig( std::string
const & module
, std::string
const & version
, int argc
, char const* argv
[] )
2404 for( int i
= 0; i
< argc
; ++i
)
2406 std::cout
<< argv
[ i
] << '\n';
2411 std::string
m2( module
);
2412 std::replace( m2
.begin(), m2
.end(), '/', '_' );
2414 std::string
m3( module
);
2415 std::replace( m3
.begin(), m3
.end(), '/', '~' );
2417 std::cout
<< "Name: boost_" << module
<< '\n';
2418 std::cout
<< "Description: Boost C++ library '" << module
<< "'\n";
2419 std::cout
<< "Version: " << version
<< '\n';
2420 std::cout
<< "URL: http://www.boost.org/libs/" << module
<< '\n';
2421 std::cout
<< "Cflags: -I${includedir}\n";
2423 if( fs::exists( module_build_path( module
) ) && fs::exists( module_source_path( module
) ) )
2425 std::cout
<< "Libs: -L${libdir} -lboost_" << m2
<< "\n";
2428 collect_primary_dependencies a1
;
2429 output_module_primary_report( m3
, a1
, false, false );
2431 if( !a1
.set_
.empty() )
2433 output_requires( "Requires", version
, a1
.set_
);
2434 std::cout
<< std::endl
;
2437 collect_primary_dependencies a2
;
2438 output_module_primary_report( m3
, a2
, true, false );
2440 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2442 a2
.set_
.erase( *i
);
2445 if( !a2
.set_
.empty() )
2447 output_requires( "Requires.private", version
, a2
.set_
);
2448 std::cout
<< std::endl
;
2454 static void output_directory_subset_report( std::string
const & module
, std::set
<std::string
> const & headers
, bool html
)
2456 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
2458 std::map
< std::string
, std::set
< std::string
> > deps
;
2459 std::map
< std::string
, std::set
< std::string
> > from
;
2461 std::ifstream
is( i
->c_str() );
2462 scan_header_dependencies( *i
, is
, deps
, from
);
2464 for( std::map
< std::string
, std::set
< std::string
> >::const_iterator j
= from
.begin(); j
!= from
.end(); ++j
)
2466 for( std::set
<std::string
>::const_iterator k
= j
->second
.begin(); k
!= j
->second
.end(); ++k
)
2468 s_header_includes
[ *k
].insert( j
->first
);
2475 module_subset_html_actions actions
;
2476 output_module_subset_report_( module
, headers
, actions
);
2480 module_subset_txt_actions actions
;
2481 output_module_subset_report_( module
, headers
, actions
);
2485 // list_buildable_dependencies
2487 struct list_buildable_dependencies_actions
: public module_overview_actions
2489 std::set
< std::string
> buildable_
;
2491 std::set
< std::string
> deps_
;
2494 list_buildable_dependencies_actions(): headers_()
2500 std::cout
<< "# Generated by `boostdep --list-buildable-dependencies`\n\n";
2507 void module_start( std::string
const & module
)
2512 if( buildable_
.count( module
) )
2514 std::cout
<< module
<< " =";
2518 void module_end( std::string
const & module
)
2520 if( buildable_
.count( module
) )
2524 std::cout
<< " headers";
2527 for( std::set
< std::string
>::iterator i
= deps_
.begin(); i
!= deps_
.end(); ++i
)
2529 std::cout
<< " " << *i
;
2532 std::cout
<< " ;\n";
2536 void module2( std::string
const & module
)
2538 if( module
== "(unknown)" ) return;
2540 if( buildable_
.count( module
) == 0 )
2546 deps_
.insert( module
);
2551 static void list_buildable_dependencies()
2553 list_buildable_dependencies_actions actions
;
2555 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
2557 if( fs::exists( module_build_path( *i
) ) && fs::exists( module_source_path( *i
) ) )
2559 actions
.buildable_
.insert( *i
);
2563 output_module_overview_report( actions
);
2568 static bool find_boost_root()
2570 for( int i
= 0; i
< 32; ++i
)
2572 if( fs::exists( "Jamroot" ) )
2577 fs::path p
= fs::current_path();
2579 if( p
== p
.root_path() )
2584 fs::current_path( p
.parent_path() );
2590 static bool is_boost_root( fs::path
const & p
)
2592 return fs::exists( p
/ "Jamroot" );
2597 class teebuf
: public std::streambuf
2601 std::streambuf
* sb1_
;
2602 std::streambuf
* sb2_
;
2606 teebuf( std::streambuf
* sb1
, std::streambuf
* sb2
): sb1_( sb1
), sb2_( sb2
)
2612 virtual int overflow( int c
)
2614 int r1
= sb1_
->sputc( c
);
2615 int r2
= sb2_
->sputc( c
);
2617 return r1
== EOF
|| r2
== EOF
? EOF
: c
;
2622 int r1
= sb1_
->pubsync();
2623 int r2
= sb2_
->pubsync();
2625 return r1
== 0 && r2
== 0? 0 : -1;
2631 class save_cout_rdbuf
2635 std::streambuf
* sb_
;
2639 save_cout_rdbuf(): sb_( std::cout
.rdbuf() )
2645 std::cout
.rdbuf( sb_
);
2651 int main( int argc
, char const* argv
[] )
2659 " boostdep --list-modules\n"
2660 " boostdep --list-buildable\n"
2661 " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
2662 " boostdep --list-exceptions\n"
2663 " boostdep --list-missing-headers\n"
2664 " boostdep --list-buildable-dependencies\n"
2666 " boostdep [options] --module-overview\n"
2667 " boostdep [options] --module-levels\n"
2668 " boostdep [options] --module-weights\n"
2670 " boostdep [options] [--primary] <module>\n"
2671 " boostdep [options] --secondary <module>\n"
2672 " boostdep [options] --reverse <module>\n"
2673 " boostdep [options] --subset <module>\n"
2674 " boostdep [options] [--header] <header>\n"
2675 " boostdep --test <module>\n"
2676 " boostdep --cmake <module>\n"
2677 " boostdep --pkgconfig <module> <version> [<var>=<value>] [<var>=<value>]...\n"
2678 " boostdep [options] --subset-for <directory>\n"
2680 " [options]: [--boost-root <path-to-boost>]\n"
2681 " [--[no-]track-sources] [--[no-]track-tests]\n"
2682 " [--html-title <title>] [--html-footer <footer>]\n"
2683 " [--html-stylesheet <stylesheet>] [--html-prefix <prefix>]\n"
2689 bool root_set
= false;
2691 for( int i
= 0; i
< argc
; ++i
)
2693 std::string option
= argv
[ i
];
2695 if( option
== "--boost-root" )
2699 fs::path
p( argv
[ ++i
] );
2701 if( is_boost_root( p
) )
2703 fs::current_path( p
);
2708 std::cerr
<< "'" << p
.string() << "': not a valid Boost root.\n";
2714 std::cerr
<< "'" << option
<< "': missing argument.\n";
2720 if( !root_set
&& !find_boost_root() )
2722 char const * env_root
= std::getenv( "BOOST_ROOT" );
2724 if( env_root
&& is_boost_root( env_root
) )
2726 fs::current_path( env_root
);
2730 std::cerr
<< "boostdep: Could not find Boost root.\n";
2739 catch( fs::filesystem_error
const & x
)
2741 std::cerr
<< x
.what() << std::endl
;
2745 bool secondary
= false;
2746 bool track_sources
= false;
2747 bool track_tests
= false;
2749 std::string html_title
= "Boost Dependency Report";
2750 std::string html_footer
;
2751 std::string html_stylesheet
;
2752 std::string html_prefix
;
2754 std::ostringstream captured_output
;
2755 teebuf
tsb( std::cout
.rdbuf(), captured_output
.rdbuf() );
2757 save_cout_rdbuf scrdb
;
2759 for( int i
= 1; i
< argc
; ++i
)
2761 std::string option
= argv
[ i
];
2763 if( option
== "--boost-root" )
2767 else if( option
== "--list-modules" )
2771 else if( option
== "--list-buildable" )
2775 else if( option
== "--title" || option
== "--html-title" )
2779 html_title
= argv
[ ++i
];
2782 else if( option
== "--footer" || option
== "--html-footer" )
2786 html_footer
= argv
[ ++i
];
2789 else if( option
== "--html-stylesheet" )
2793 html_stylesheet
= argv
[ ++i
];
2796 else if( option
== "--html-prefix" )
2800 html_prefix
= argv
[ ++i
];
2803 else if( option
== "--html" )
2808 output_html_header( html_title
, html_stylesheet
, html_prefix
);
2811 else if( option
== "--track-sources" )
2813 track_sources
= true;
2815 else if( option
== "--no-track-sources" )
2817 track_sources
= false;
2819 else if( option
== "--track-tests" )
2823 else if( option
== "--no-track-tests" )
2825 track_tests
= false;
2827 else if( option
== "--primary" )
2831 output_module_primary_report( argv
[ ++i
], html
, track_sources
, track_tests
);
2834 else if( option
== "--secondary" )
2838 enable_secondary( secondary
, track_sources
, track_tests
);
2839 output_module_secondary_report( argv
[ ++i
], html
);
2842 else if( option
== "--reverse" )
2846 enable_secondary( secondary
, track_sources
, track_tests
);
2847 output_module_reverse_report( argv
[ ++i
], html
);
2850 else if( option
== "--header" )
2854 enable_secondary( secondary
, track_sources
, track_tests
);
2855 output_header_report( argv
[ ++i
], html
);
2858 else if( option
== "--subset" )
2862 enable_secondary( secondary
, track_sources
, track_tests
);
2863 output_module_subset_report( argv
[ ++i
], track_sources
, track_tests
, html
);
2866 else if( option
== "--test" )
2870 output_module_test_report( argv
[ ++i
] );
2873 else if( option
== "--cmake" )
2877 output_module_cmake_report( argv
[ ++i
] );
2880 else if( option
== "--module-levels" )
2882 enable_secondary( secondary
, track_sources
, track_tests
);
2883 output_module_level_report( html
);
2885 else if( option
== "--module-overview" )
2887 enable_secondary( secondary
, track_sources
, track_tests
);
2888 output_module_overview_report( html
);
2890 else if( option
== "--module-weights" )
2892 enable_secondary( secondary
, track_sources
, track_tests
);
2893 output_module_weight_report( html
);
2895 else if( option
== "--list-dependencies" )
2897 enable_secondary( secondary
, track_sources
, track_tests
);
2898 list_dependencies();
2900 else if( option
== "--list-exceptions" )
2904 else if( option
== "--list-missing-headers" )
2906 list_missing_headers();
2908 else if( option
== "--pkgconfig" )
2912 std::string module
= argv
[ ++i
];
2913 std::string version
= argv
[ ++i
];
2917 output_pkgconfig( module
, version
, argc
- i
, argv
+ i
);
2921 std::cerr
<< "'" << option
<< "': missing module or version.\n";
2926 else if( option
== "--subset-for" )
2930 std::string module
= argv
[ ++i
];
2932 enable_secondary( secondary
, track_sources
, track_tests
);
2934 std::set
<std::string
> headers
;
2935 add_module_headers( module
, headers
);
2937 output_directory_subset_report( module
, headers
, html
);
2941 std::cerr
<< "'" << option
<< "': missing argument.\n";
2946 else if( option
== "--list-buildable-dependencies" )
2948 enable_secondary( secondary
, true, false );
2949 list_buildable_dependencies();
2951 else if( option
== "--capture-output" )
2953 std::cout
.rdbuf( &tsb
);
2955 else if( option
== "--compare-output" )
2959 std::string fn
= argv
[ ++i
];
2960 std::fstream
is( fn
.c_str() );
2964 std::cerr
<< option
<< " '" << fn
<< "': could not open file.\n";
2968 std::istreambuf_iterator
<char> first( is
), last
;
2969 std::string
fc( first
, last
);
2971 if( fc
!= captured_output
.str() )
2973 std::cerr
<< option
<< " '" << fn
<< "': output does not match; expected output:\n---\n" << fc
<< "---\n";
2977 std::cerr
<< option
<< " '" << fn
<< "': output matches.\n";
2978 captured_output
.str( "" );
2982 std::cerr
<< "'" << option
<< "': missing argument.\n";
2986 else if( s_modules
.count( option
) )
2988 output_module_primary_report( option
, html
, track_sources
, track_tests
);
2990 else if( s_header_map
.count( option
) )
2992 enable_secondary( secondary
, track_sources
, track_tests
);
2993 output_header_report( option
, html
);
2997 std::cerr
<< "'" << option
<< "': not an option, module or header.\n";
3003 output_html_footer( html_footer
);