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 fs::path
module_meta_path( std::string module
)
207 std::replace( module
.begin(), module
.end(), '~', '/' );
208 return fs::path( "libs" ) / module
/ "meta";
211 static void scan_module_path( fs::path
const & dir
, bool remove_prefix
, std::map
< std::string
, std::set
< std::string
> > & deps
, std::map
< std::string
, std::set
< std::string
> > & from
)
213 size_t n
= dir
.generic_string().size();
215 if( fs::exists( dir
) )
217 fs::recursive_directory_iterator
it( dir
), last
;
219 for( ; it
!= last
; ++it
)
221 if( it
->status().type() == fs::directory_file
)
226 std::string header
= it
->path().generic_string();
230 header
= header
.substr( n
+1 );
233 fs::ifstream
is( it
->path() );
235 scan_header_dependencies( header
, is
, deps
, from
);
240 static void scan_module_dependencies( std::string
const & module
, module_primary_actions
& actions
, bool track_sources
, bool track_tests
, bool include_self
)
242 // module -> [ header, header... ]
243 std::map
< std::string
, std::set
< std::string
> > deps
;
245 // header -> included from [ header, header... ]
246 std::map
< std::string
, std::set
< std::string
> > from
;
248 scan_module_path( module_include_path( module
), true, deps
, from
);
252 scan_module_path( module_source_path( module
), false, deps
, from
);
257 scan_module_path( module_test_path( module
), false, deps
, from
);
260 actions
.heading( module
);
262 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= deps
.begin(); i
!= deps
.end(); ++i
)
264 if( i
->first
== module
&& !include_self
) continue;
266 actions
.module_start( i
->first
);
268 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
270 actions
.header_start( *j
);
272 std::set
< std::string
> const & f
= from
[ *j
];
274 for( std::set
< std::string
>::const_iterator k
= f
.begin(); k
!= f
.end(); ++k
)
276 actions
.from_header( *k
);
279 actions
.header_end( *j
);
282 actions
.module_end( i
->first
);
286 // module depends on [ module, module... ]
287 static std::map
< std::string
, std::set
< std::string
> > s_module_deps
;
289 // header is included by [header, header...]
290 static std::map
< std::string
, std::set
< std::string
> > s_header_deps
;
292 // [ module, module... ] depend on module
293 static std::map
< std::string
, std::set
< std::string
> > s_reverse_deps
;
295 // header includes [header, header...]
296 static std::map
< std::string
, std::set
< std::string
> > s_header_includes
;
298 struct build_mdmap_actions
: public module_primary_actions
301 std::string module2_
;
304 void heading( std::string
const & module
)
309 void module_start( std::string
const & module
)
311 if( module
!= module_
)
313 s_module_deps
[ module_
].insert( module
);
314 s_reverse_deps
[ module
].insert( module_
);
320 void module_end( std::string
const & /*module*/ )
324 void header_start( std::string
const & header
)
329 void header_end( std::string
const & /*header*/ )
333 void from_header( std::string
const & header
)
335 if( module_
!= module2_
)
337 s_header_deps
[ header_
].insert( header
);
340 s_header_includes
[ header
].insert( header_
);
344 static void build_module_dependency_map( bool track_sources
, bool track_tests
)
346 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
348 build_mdmap_actions actions
;
349 scan_module_dependencies( *i
, actions
, track_sources
, track_tests
, true );
353 static void output_module_primary_report( std::string
const & module
, module_primary_actions
& actions
, bool track_sources
, bool track_tests
)
357 scan_module_dependencies( module
, actions
, track_sources
, track_tests
, false );
359 catch( fs::filesystem_error
const & x
)
361 std::cout
<< x
.what() << std::endl
;
365 struct module_secondary_actions
367 virtual void heading( std::string
const & module
) = 0;
369 virtual void module_start( std::string
const & module
) = 0;
370 virtual void module_end( std::string
const & module
) = 0;
372 virtual void module_adds( std::string
const & module
) = 0;
375 static void exclude( std::set
< std::string
> & x
, std::set
< std::string
> const & y
)
377 for( std::set
< std::string
>::const_iterator i
= y
.begin(); i
!= y
.end(); ++i
)
383 static void output_module_secondary_report( std::string
const & module
, std::set
< std::string
> deps
, module_secondary_actions
& actions
)
385 actions
.heading( module
);
387 deps
.insert( module
);
389 // build transitive closure
393 std::set
< std::string
> deps2( deps
);
395 for( std::set
< std::string
>::iterator i
= deps
.begin(); i
!= deps
.end(); ++i
)
397 std::set
< std::string
> deps3
= s_module_deps
[ *i
];
399 exclude( deps3
, deps
);
406 actions
.module_start( *i
);
408 for( std::set
< std::string
>::iterator j
= deps3
.begin(); j
!= deps3
.end(); ++j
)
410 actions
.module_adds( *j
);
413 actions
.module_end( *i
);
415 deps2
.insert( deps3
.begin(), deps3
.end() );
429 static void output_module_secondary_report( std::string
const & module
, module_secondary_actions
& actions
)
431 output_module_secondary_report( module
, s_module_deps
[ module
], actions
);
434 struct header_inclusion_actions
436 virtual void heading( std::string
const & header
, std::string
const & module
) = 0;
438 virtual void module_start( std::string
const & module
) = 0;
439 virtual void module_end( std::string
const & module
) = 0;
441 virtual void header( std::string
const & header
) = 0;
444 static std::string
module_for_header( std::string header
)
447 std::map
<std::string
, std::string
>::const_iterator i
= s_header_map
.find( header
);
449 if( i
!= s_header_map
.end() )
455 if( header
.substr( 0, 5 ) == "libs/" )
457 header
= header
.substr( 5 );
459 else if( header
.substr( 0, 5 ) == "test/" )
461 header
= header
.substr( 5 );
465 return std::string();
468 for( std::set
<std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
470 std::string module
= *i
;
471 std::replace( module
.begin(), module
.end(), '~', '/' );
473 if( header
.substr( 0, module
.size() + 1 ) == module
+ '/' )
479 return std::string();
482 static void output_header_inclusion_report( std::string
const & header
, header_inclusion_actions
& actions
)
484 std::string module
= s_header_map
[ header
];
486 actions
.heading( header
, module
);
488 std::set
< std::string
> from
= s_header_deps
[ header
];
490 // classify 'from' dependencies by module
492 // module -> [header, header...]
493 std::map
< std::string
, std::set
< std::string
> > from2
;
495 for( std::set
< std::string
>::iterator i
= from
.begin(); i
!= from
.end(); ++i
)
497 from2
[ module_for_header( *i
) ].insert( *i
);
500 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= from2
.begin(); i
!= from2
.end(); ++i
)
502 actions
.module_start( i
->first
);
504 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
506 actions
.header( *j
);
509 actions
.module_end( i
->first
);
513 // output_module_primary_report
515 struct module_primary_txt_actions
: public module_primary_actions
517 void heading( std::string
const & module
)
519 std::cout
<< "Primary dependencies for " << module
<< ":\n\n";
522 void module_start( std::string
const & module
)
524 std::cout
<< module
<< ":\n";
527 void module_end( std::string
const & /*module*/ )
532 void header_start( std::string
const & header
)
534 std::cout
<< " <" << header
<< ">\n";
537 void header_end( std::string
const & /*header*/ )
541 void from_header( std::string
const & header
)
543 std::cout
<< " from <" << header
<< ">\n";
547 struct module_primary_html_actions
: public module_primary_actions
549 void heading( std::string
const & module
)
551 std::cout
<< "\n\n<h1 id=\"primary-dependencies\">Primary dependencies for <em>" << module
<< "</em></h1>\n";
554 void module_start( std::string
const & module
)
556 std::cout
<< " <h2 id=\"" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2>\n";
559 void module_end( std::string
const & /*module*/ )
563 void header_start( std::string
const & header
)
565 std::cout
<< " <h3><code><" << header
<< "></code></h3><ul>\n";
568 void header_end( std::string
const & /*header*/ )
570 std::cout
<< " </ul>\n";
573 void from_header( std::string
const & header
)
575 std::cout
<< " <li>from <code><" << header
<< "></code></li>\n";
579 static void output_module_primary_report( std::string
const & module
, bool html
, bool track_sources
, bool track_tests
)
583 module_primary_html_actions actions
;
584 output_module_primary_report( module
, actions
, track_sources
, track_tests
);
588 module_primary_txt_actions actions
;
589 output_module_primary_report( module
, actions
, track_sources
, track_tests
);
593 // output_module_secondary_report
595 struct module_secondary_txt_actions
: public module_secondary_actions
597 void heading( std::string
const & module
)
599 std::cout
<< "Secondary dependencies for " << module
<< ":\n\n";
602 void module_start( std::string
const & module
)
604 std::cout
<< module
<< ":\n";
607 void module_end( std::string
const & /*module*/ )
612 void module_adds( std::string
const & module
)
614 std::cout
<< " adds " << module
<< "\n";
618 struct module_secondary_html_actions
: public module_secondary_actions
622 void heading( std::string
const & module
)
624 std::cout
<< "\n\n<h1 id=\"secondary-dependencies\">Secondary dependencies for <em>" << module
<< "</em></h1>\n";
627 void module_start( std::string
const & module
)
629 std::cout
<< " <h2><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
633 void module_end( std::string
const & /*module*/ )
635 std::cout
<< " </ul>\n";
638 void module_adds( std::string
const & module
)
640 std::cout
<< " <li><a href=\"" << m2_
<< ".html#" << module
<< "\">adds <em>" << module
<< "</em></a></li>\n";
644 static void output_module_secondary_report( std::string
const & module
, bool html
)
648 module_secondary_html_actions actions
;
649 output_module_secondary_report( module
, actions
);
653 module_secondary_txt_actions actions
;
654 output_module_secondary_report( module
, actions
);
658 // output_header_report
660 struct header_inclusion_txt_actions
: public header_inclusion_actions
662 void heading( std::string
const & header
, std::string
const & module
)
664 std::cout
<< "Inclusion report for <" << header
<< "> (in module " << module
<< "):\n\n";
667 void module_start( std::string
const & module
)
669 std::cout
<< " from " << module
<< ":\n";
672 void module_end( std::string
const & /*module*/ )
677 void header( std::string
const & header
)
679 std::cout
<< " <" << header
<< ">\n";
683 struct header_inclusion_html_actions
: public header_inclusion_actions
685 void heading( std::string
const & header
, std::string
const & module
)
687 std::cout
<< "<h1>Inclusion report for <code><" << header
<< "></code> (in module <em>" << module
<< "</em>)</h1>\n";
690 void module_start( std::string
const & module
)
692 std::cout
<< " <h2>From <a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
695 void module_end( std::string
const & /*module*/ )
697 std::cout
<< " </ul>\n";
700 void header( std::string
const & header
)
702 std::cout
<< " <li><code><" << header
<< "></code></li>\n";
706 static void output_header_report( std::string
const & header
, bool html
)
710 header_inclusion_html_actions actions
;
711 output_header_inclusion_report( header
, actions
);
715 header_inclusion_txt_actions actions
;
716 output_header_inclusion_report( header
, actions
);
720 // output_module_reverse_report
722 struct module_reverse_actions
724 virtual void heading( std::string
const & module
) = 0;
726 virtual void module_start( std::string
const & module
) = 0;
727 virtual void module_end( std::string
const & module
) = 0;
729 virtual void header_start( std::string
const & header
) = 0;
730 virtual void header_end( std::string
const & header
) = 0;
732 virtual void from_header( std::string
const & header
) = 0;
735 static void output_module_reverse_report( std::string
const & module
, module_reverse_actions
& actions
)
737 actions
.heading( module
);
739 std::set
< std::string
> const from
= s_reverse_deps
[ module
];
741 for( std::set
< std::string
>::const_iterator i
= from
.begin(); i
!= from
.end(); ++i
)
743 actions
.module_start( *i
);
745 for( std::map
< std::string
, std::set
< std::string
> >::iterator j
= s_header_deps
.begin(); j
!= s_header_deps
.end(); ++j
)
747 if( module_for_header( j
->first
) == module
)
749 bool header_started
= false;
751 for( std::set
< std::string
>::iterator k
= j
->second
.begin(); k
!= j
->second
.end(); ++k
)
753 if( module_for_header( *k
) == *i
)
755 if( !header_started
)
757 actions
.header_start( j
->first
);
759 header_started
= true;
762 actions
.from_header( *k
);
768 actions
.header_end( j
->first
);
773 actions
.module_end( *i
);
777 struct module_reverse_txt_actions
: public module_reverse_actions
779 void heading( std::string
const & module
)
781 std::cout
<< "Reverse dependencies for " << module
<< ":\n\n";
784 void module_start( std::string
const & module
)
786 std::cout
<< module
<< ":\n";
789 void module_end( std::string
const & /*module*/ )
794 void header_start( std::string
const & header
)
796 std::cout
<< " <" << header
<< ">\n";
799 void header_end( std::string
const & /*header*/ )
803 void from_header( std::string
const & header
)
805 std::cout
<< " from <" << header
<< ">\n";
809 struct module_reverse_html_actions
: public module_reverse_actions
811 void heading( std::string
const & module
)
813 std::cout
<< "\n\n<h1 id=\"reverse-dependencies\">Reverse dependencies for <em>" << module
<< "</em></h1>\n";
816 void module_start( std::string
const & module
)
818 std::cout
<< " <h2 id=\"reverse-" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2>\n";
821 void module_end( std::string
const & /*module*/ )
825 void header_start( std::string
const & header
)
827 std::cout
<< " <h3><code><" << header
<< "></code></h3><ul>\n";
830 void header_end( std::string
const & /*header*/ )
832 std::cout
<< " </ul>\n";
835 void from_header( std::string
const & header
)
837 std::cout
<< " <li>from <code><" << header
<< "></code></li>\n";
841 static void output_module_reverse_report( std::string
const & module
, bool html
)
845 module_reverse_html_actions actions
;
846 output_module_reverse_report( module
, actions
);
850 module_reverse_txt_actions actions
;
851 output_module_reverse_report( module
, actions
);
855 // module_level_report
857 int const unknown_level
= INT_MAX
/ 2;
859 struct module_level_actions
861 virtual void begin() = 0;
862 virtual void end() = 0;
864 virtual void level_start( int level
) = 0;
865 virtual void level_end( int level
) = 0;
867 virtual void module_start( std::string
const & module
) = 0;
868 virtual void module_end( std::string
const & module
) = 0;
870 virtual void module2( std::string
const & module
, int level
) = 0;
873 static void output_module_level_report( module_level_actions
& actions
)
875 // build module level map
877 std::map
< std::string
, int > level_map
;
879 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
881 if( s_module_deps
[ *i
].empty() )
884 // std::cerr << *i << ": " << 0 << std::endl;
888 level_map
[ *i
] = unknown_level
;
892 // build transitive closure to see through cycles
894 std::map
< std::string
, std::set
< std::string
> > deps2
= s_module_deps
;
903 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= deps2
.begin(); i
!= deps2
.end(); ++i
)
905 std::set
< std::string
> tmp
= i
->second
;
907 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
909 std::set
< std::string
> tmp2
= deps2
[ *j
];
910 tmp
.insert( tmp2
.begin(), tmp2
.end() );
913 if( tmp
.size() != i
->second
.size() )
923 // compute acyclic levels
925 for( int k
= 1, n
= s_modules
.size(); k
< n
; ++k
)
927 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= s_module_deps
.begin(); i
!= s_module_deps
.end(); ++i
)
929 // i->first depends on i->second
931 if( level_map
[ i
->first
] >= unknown_level
)
935 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
937 level
= std::max( level
, level_map
[ *j
] + 1 );
942 level_map
[ i
->first
] = level
;
943 // std::cerr << i->first << ": " << level << std::endl;
949 // min_level_map[ M ] == L means the level is unknown, but at least L
950 std::map
< std::string
, int > min_level_map
;
952 // initialize min_level_map for acyclic dependencies
954 for( std::map
< std::string
, int >::iterator i
= level_map
.begin(); i
!= level_map
.end(); ++i
)
956 if( i
->second
< unknown_level
)
958 min_level_map
[ i
->first
] = i
->second
;
962 // compute levels for cyclic modules
964 for( int k
= 1, n
= s_modules
.size(); k
< n
; ++k
)
966 for( std::map
< std::string
, std::set
< std::string
> >::iterator i
= s_module_deps
.begin(); i
!= s_module_deps
.end(); ++i
)
968 if( level_map
[ i
->first
] >= unknown_level
)
972 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
974 int jl
= level_map
[ *j
];
976 if( jl
< unknown_level
)
978 level
= std::max( level
, jl
+ 1 );
982 int ml
= min_level_map
[ *j
];
984 if( deps2
[ *j
].count( i
->first
) == 0 )
986 // *j does not depend on i->first, so
987 // the level of i->first is at least
988 // 1 + the minimum level of *j
993 level
= std::max( level
, ml
);
997 min_level_map
[ i
->first
] = level
;
1002 // reverse level map
1004 std::map
< int, std::set
< std::string
> > reverse_level_map
;
1006 for( std::map
< std::string
, int >::iterator i
= level_map
.begin(); i
!= level_map
.end(); ++i
)
1008 int level
= i
->second
;
1010 if( level
>= unknown_level
)
1012 int min_level
= min_level_map
[ i
->first
];
1014 if( min_level
!= 0 )
1020 reverse_level_map
[ level
].insert( i
->first
);
1027 for( std::map
< int, std::set
< std::string
> >::iterator i
= reverse_level_map
.begin(); i
!= reverse_level_map
.end(); ++i
)
1029 actions
.level_start( i
->first
);
1031 for( std::set
< std::string
>::iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1033 actions
.module_start( *j
);
1035 std::set
< std::string
> mdeps
= s_module_deps
[ *j
];
1037 for( std::set
< std::string
>::iterator k
= mdeps
.begin(); k
!= mdeps
.end(); ++k
)
1039 int level
= level_map
[ *k
];
1041 if( level
>= unknown_level
)
1043 int min_level
= min_level_map
[ *k
];
1045 if( min_level
!= 0 )
1051 actions
.module2( *k
, level
);
1054 actions
.module_end( *j
);
1057 actions
.level_end( i
->first
);
1063 struct module_level_txt_actions
: public module_level_actions
1069 std::cout
<< "Module Levels:\n\n";
1076 void level_start( int level
)
1078 if( level
>= unknown_level
)
1080 std::cout
<< "Level (undetermined):\n";
1084 std::cout
<< "Level " << level
<< ":\n";
1090 void level_end( int /*level*/ )
1095 void module_start( std::string
const & module
)
1097 std::cout
<< " " << module
;
1105 void module_end( std::string
const & /*module*/ )
1110 void module2( std::string
const & module
, int level
)
1112 std::cout
<< " " << module
<< "(";
1114 if( level
>= unknown_level
)
1127 struct module_level_html_actions
: public module_level_actions
1133 std::cout
<< "<div id='module-levels'><h1>Module Levels</h1>\n";
1138 std::cout
<< "</div>\n";
1141 void level_start( int level
)
1143 if( level
>= unknown_level
)
1145 std::cout
<< " <h2>Level <em>undetermined</em></h2>\n";
1149 std::cout
<< " <h2 id='level:" << level
<< "'>Level " << level
<< "</h2>\n";
1155 void level_end( int /*level*/ )
1159 void module_start( std::string
const & module
)
1161 std::cout
<< " <h3 id='" << module
<< "'><a href=\"" << module
<< ".html\">" << module
<< "</a></h3><p class='primary-list'>";
1164 void module_end( std::string
const & /*module*/ )
1166 std::cout
<< "</p>\n";
1169 void module2( std::string
const & module
, int level
)
1173 bool important
= level
< unknown_level
&& level
> 1 && level
>= level_
- 1;
1177 std::cout
<< "<strong>";
1180 std::cout
<< module
;
1182 if( level
< unknown_level
)
1184 std::cout
<< "<sup>" << level
<< "</sup>";
1189 std::cout
<< "</strong>";
1194 static void output_module_level_report( bool html
)
1198 module_level_html_actions actions
;
1199 output_module_level_report( actions
);
1203 module_level_txt_actions actions
;
1204 output_module_level_report( actions
);
1208 // module_overview_report
1210 struct module_overview_actions
1212 virtual void begin() = 0;
1213 virtual void end() = 0;
1215 virtual void module_start( std::string
const & module
) = 0;
1216 virtual void module_end( std::string
const & module
) = 0;
1218 virtual void module2( std::string
const & module
) = 0;
1221 static void output_module_overview_report( module_overview_actions
& actions
)
1225 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1227 actions
.module_start( *i
);
1229 std::set
< std::string
> const mdeps
= s_module_deps
[ *i
];
1231 for( std::set
< std::string
>::const_iterator j
= mdeps
.begin(); j
!= mdeps
.end(); ++j
)
1233 actions
.module2( *j
);
1236 actions
.module_end( *i
);
1242 struct module_overview_txt_actions
: public module_overview_actions
1248 std::cout
<< "Module Overview:\n\n";
1255 void module_start( std::string
const & module
)
1257 std::cout
<< module
;
1261 void module_end( std::string
const & /*module*/ )
1266 void module2( std::string
const & module
)
1274 std::cout
<< " " << module
;
1278 struct module_overview_html_actions
: public module_overview_actions
1282 std::cout
<< "<div id='module-overview'><h1>Module Overview</h1>\n";
1287 std::cout
<< "</div>\n";
1290 void module_start( std::string
const & module
)
1292 std::cout
<< " <h2 id='" << module
<< "'><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><p class='primary-list'>";
1295 void module_end( std::string
const & /*module*/ )
1297 std::cout
<< "</p>\n";
1300 void module2( std::string
const & module
)
1302 std::cout
<< " " << module
;
1306 static void output_module_overview_report( bool html
)
1310 module_overview_html_actions actions
;
1311 output_module_overview_report( actions
);
1315 module_overview_txt_actions actions
;
1316 output_module_overview_report( actions
);
1320 // list_dependencies
1322 struct list_dependencies_actions
: public module_overview_actions
1332 void module_start( std::string
const & module
)
1334 std::cout
<< module
<< " ->";
1337 void module_end( std::string
const & /*module*/ )
1342 void module2( std::string
const & module
)
1344 if( module
!= "(unknown)" )
1346 std::cout
<< " " << module
;
1351 static void list_dependencies()
1353 list_dependencies_actions actions
;
1354 output_module_overview_report( actions
);
1359 static void output_html_header( std::string
const & title
, std::string
const & stylesheet
, std::string
const & prefix
)
1361 std::cout
<< "<html>\n";
1362 std::cout
<< "<head>\n";
1363 std::cout
<< "<title>" << title
<< "</title>\n";
1365 if( !stylesheet
.empty() )
1367 std::cout
<< "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet
<< "\" />\n";
1370 std::cout
<< "</head>\n";
1371 std::cout
<< "<body>\n";
1373 if( !prefix
.empty() )
1375 std::cout
<< prefix
<< std::endl
;
1379 static void output_html_footer( std::string
const & footer
)
1381 std::cout
<< "<hr />\n";
1382 std::cout
<< "<p class=\"footer\">" << footer
<< "</p>\n";
1383 std::cout
<< "</body>\n";
1384 std::cout
<< "</html>\n";
1387 static void enable_secondary( bool & secondary
, bool track_sources
, bool track_tests
)
1393 build_module_dependency_map( track_sources
, track_tests
);
1395 catch( fs::filesystem_error
const & x
)
1397 std::cout
<< x
.what() << std::endl
;
1404 static void list_modules()
1406 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1408 std::cout
<< *i
<< "\n";
1412 static void list_buildable()
1414 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1416 if( fs::exists( module_build_path( *i
) ) && fs::exists( module_source_path( *i
) ) )
1418 std::cout
<< *i
<< "\n";
1423 // module_weight_report
1425 struct module_weight_actions
1427 virtual void begin() = 0;
1428 virtual void end() = 0;
1430 virtual void weight_start( int weight
) = 0;
1431 virtual void weight_end( int weight
) = 0;
1433 virtual void module_start( std::string
const & module
) = 0;
1434 virtual void module_end( std::string
const & module
) = 0;
1436 virtual void module_primary_start() = 0;
1437 virtual void module_primary( std::string
const & module
, int weight
) = 0;
1438 virtual void module_primary_end() = 0;
1440 virtual void module_secondary_start() = 0;
1441 virtual void module_secondary( std::string
const & module
, int weight
) = 0;
1442 virtual void module_secondary_end() = 0;
1445 static void output_module_weight_report( module_weight_actions
& actions
)
1447 // gather secondary dependencies
1449 struct build_secondary_deps
: public module_secondary_actions
1451 std::map
< std::string
, std::set
< std::string
> > * pm_
;
1453 build_secondary_deps( std::map
< std::string
, std::set
< std::string
> > * pm
): pm_( pm
)
1457 std::string module_
;
1459 void heading( std::string
const & module
)
1464 void module_start( std::string
const & /*module*/ )
1468 void module_end( std::string
const & /*module*/ )
1472 void module_adds( std::string
const & module
)
1474 (*pm_
)[ module_
].insert( module
);
1478 std::map
< std::string
, std::set
< std::string
> > secondary_deps
;
1480 build_secondary_deps
bsd( &secondary_deps
);
1482 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1484 output_module_secondary_report( *i
, bsd
);
1489 std::map
< int, std::set
< std::string
> > modules_by_weight
;
1491 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
1493 int w
= s_module_deps
[ *i
].size() + secondary_deps
[ *i
].size();
1494 modules_by_weight
[ w
].insert( *i
);
1501 for( std::map
< int, std::set
< std::string
> >::const_iterator i
= modules_by_weight
.begin(); i
!= modules_by_weight
.end(); ++i
)
1503 actions
.weight_start( i
->first
);
1505 for( std::set
< std::string
>::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1507 actions
.module_start( *j
);
1509 if( !s_module_deps
[ *j
].empty() )
1511 actions
.module_primary_start();
1513 for( std::set
< std::string
>::const_iterator k
= s_module_deps
[ *j
].begin(); k
!= s_module_deps
[ *j
].end(); ++k
)
1515 int w
= s_module_deps
[ *k
].size() + secondary_deps
[ *k
].size();
1516 actions
.module_primary( *k
, w
);
1519 actions
.module_primary_end();
1522 if( !secondary_deps
[ *j
].empty() )
1524 actions
.module_secondary_start();
1526 for( std::set
< std::string
>::const_iterator k
= secondary_deps
[ *j
].begin(); k
!= secondary_deps
[ *j
].end(); ++k
)
1528 int w
= s_module_deps
[ *k
].size() + secondary_deps
[ *k
].size();
1529 actions
.module_secondary( *k
, w
);
1532 actions
.module_secondary_end();
1535 actions
.module_end( *j
);
1538 actions
.weight_end( i
->first
);
1544 struct module_weight_txt_actions
: public module_weight_actions
1548 std::cout
<< "Module Weights:\n\n";
1555 void weight_start( int weight
)
1557 std::cout
<< "Weight " << weight
<< ":\n";
1560 void weight_end( int /*weight*/ )
1565 void module_start( std::string
const & module
)
1567 std::cout
<< " " << module
;
1570 void module_end( std::string
const & /*module*/ )
1575 void module_primary_start()
1580 void module_primary( std::string
const & module
, int weight
)
1582 std::cout
<< " " << module
<< "(" << weight
<< ")";
1585 void module_primary_end()
1589 void module_secondary_start()
1594 void module_secondary( std::string
const & module
, int /*weight*/ )
1596 std::cout
<< " " << module
;
1599 void module_secondary_end()
1604 struct module_weight_html_actions
: public module_weight_actions
1610 std::cout
<< "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
1615 std::cout
<< "</div>\n";
1618 void weight_start( int weight
)
1620 std::cout
<< " <h2 id='weight:" << weight
<< "'>Weight " << weight
<< "</h2>\n";
1624 void weight_end( int /*weight*/ )
1628 void module_start( std::string
const & module
)
1630 std::cout
<< " <h3 id='" << module
<< "'><a href=\"" << module
<< ".html\">" << module
<< "</a></h3>";
1633 void module_end( std::string
const & /*module*/ )
1638 void module_primary_start()
1640 std::cout
<< "<p class='primary-list'>";
1643 void module_primary( std::string
const & module
, int weight
)
1647 bool heavy
= weight
>= 0.8 * weight_
;
1651 std::cout
<< "<strong>";
1654 std::cout
<< module
<< "<sup>" << weight
<< "</sup>";
1658 std::cout
<< "</strong>";
1662 void module_primary_end()
1664 std::cout
<< "</p>";
1667 void module_secondary_start()
1669 std::cout
<< "<p class='secondary-list'>";
1672 void module_secondary( std::string
const & module
, int /*weight*/ )
1674 std::cout
<< " " << module
;
1677 void module_secondary_end()
1679 std::cout
<< "</p>";
1683 static void output_module_weight_report( bool html
)
1687 module_weight_html_actions actions
;
1688 output_module_weight_report( actions
);
1692 module_weight_txt_actions actions
;
1693 output_module_weight_report( actions
);
1697 // output_module_subset_report
1699 struct module_subset_actions
1701 virtual void heading( std::string
const & module
) = 0;
1703 virtual void module_start( std::string
const & module
) = 0;
1704 virtual void module_end( std::string
const & module
) = 0;
1706 virtual void from_path( std::vector
<std::string
> const & path
) = 0;
1709 static void add_module_headers( fs::path
const & dir
, std::set
<std::string
> & headers
)
1711 if( fs::exists( dir
) )
1713 fs::recursive_directory_iterator
it( dir
), last
;
1715 for( ; it
!= last
; ++it
)
1717 if( it
->status().type() == fs::directory_file
)
1722 headers
.insert( it
->path().generic_string() );
1727 static void output_module_subset_report_( std::string
const & module
, std::set
<std::string
> const & headers
, module_subset_actions
& actions
)
1729 // build header closure
1731 // header -> (header)*
1732 std::map
< std::string
, std::set
<std::string
> > inc2
;
1734 // (header, header) -> path
1735 std::map
< std::pair
<std::string
, std::string
>, std::vector
<std::string
> > paths
;
1737 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
1739 std::set
<std::string
> & s
= inc2
[ *i
];
1741 s
= s_header_includes
[ *i
];
1743 for( std::set
<std::string
>::const_iterator j
= s
.begin(); j
!= s
.end(); ++j
)
1745 std::vector
<std::string
> & v
= paths
[ std::make_pair( *i
, *j
) ];
1757 for( std::map
< std::string
, std::set
<std::string
> >::iterator i
= inc2
.begin(); i
!= inc2
.end(); ++i
)
1759 std::set
<std::string
> & s2
= i
->second
;
1761 for( std::set
<std::string
>::const_iterator j
= s2
.begin(); j
!= s2
.end(); ++j
)
1763 std::set
<std::string
> const & s
= s_header_includes
[ *j
];
1765 for( std::set
<std::string
>::const_iterator k
= s
.begin(); k
!= s
.end(); ++k
)
1767 if( s2
.count( *k
) == 0 )
1771 std::vector
<std::string
> const & v1
= paths
[ std::make_pair( i
->first
, *j
) ];
1772 std::vector
<std::string
> & v2
= paths
[ std::make_pair( i
->first
, *k
) ];
1786 // module -> header -> path [header -> header -> header]
1787 std::map
< std::string
, std::map
< std::string
, std::vector
<std::string
> > > subset
;
1789 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
1791 std::set
<std::string
> const & s
= inc2
[ *i
];
1793 for( std::set
<std::string
>::const_iterator j
= s
.begin(); j
!= s
.end(); ++j
)
1795 std::string
const & m
= s_header_map
[ *j
];
1797 if( m
.empty() ) continue;
1799 std::vector
<std::string
> const & path
= paths
[ std::make_pair( *i
, *j
) ];
1801 if( subset
.count( m
) == 0 || subset
[ m
].count( *i
) == 0 || subset
[ m
][ *i
].size() > path
.size() )
1803 subset
[ m
][ *i
] = path
;
1808 actions
.heading( module
);
1810 for( std::map
< std::string
, std::map
< std::string
, std::vector
<std::string
> > >::const_iterator i
= subset
.begin(); i
!= subset
.end(); ++i
)
1812 if( i
->first
== module
) continue;
1814 actions
.module_start( i
->first
);
1818 for( std::map
< std::string
, std::vector
<std::string
> >::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end() && k
< 4; ++j
, ++k
)
1820 actions
.from_path( j
->second
);
1823 actions
.module_end( i
->first
);
1827 static void output_module_subset_report( std::string
const & module
, bool track_sources
, bool track_tests
, module_subset_actions
& actions
)
1829 std::set
<std::string
> headers
= s_module_headers
[ module
];
1833 add_module_headers( module_source_path( module
), headers
);
1838 add_module_headers( module_test_path( module
), headers
);
1841 output_module_subset_report_( module
, headers
, actions
);
1844 struct module_subset_txt_actions
: public module_subset_actions
1846 void heading( std::string
const & module
)
1848 std::cout
<< "Subset dependencies for " << module
<< ":\n\n";
1851 void module_start( std::string
const & module
)
1853 std::cout
<< module
<< ":\n";
1856 void module_end( std::string
const & /*module*/ )
1861 void from_path( std::vector
<std::string
> const & path
)
1863 for( std::vector
<std::string
>::const_iterator i
= path
.begin(); i
!= path
.end(); ++i
)
1865 if( i
== path
.begin() )
1871 std::cout
<< " -> ";
1881 struct module_subset_html_actions
: public module_subset_actions
1883 void heading( std::string
const & module
)
1885 std::cout
<< "\n\n<h1 id=\"subset-dependencies\">Subset dependencies for <em>" << module
<< "</em></h1>\n";
1888 void module_start( std::string
const & module
)
1890 std::cout
<< " <h2 id=\"subset-" << module
<< "\"><a href=\"" << module
<< ".html\"><em>" << module
<< "</em></a></h2><ul>\n";
1893 void module_end( std::string
const & /*module*/ )
1895 std::cout
<< "</ul>\n";
1898 void from_path( std::vector
<std::string
> const & path
)
1900 std::cout
<< " <li>";
1902 for( std::vector
<std::string
>::const_iterator i
= path
.begin(); i
!= path
.end(); ++i
)
1904 if( i
!= path
.begin() )
1906 std::cout
<< " ⇢ ";
1909 std::cout
<< "<code>" << *i
<< "</code>";
1912 std::cout
<< "</li>\n";
1916 static void output_module_subset_report( std::string
const & module
, bool track_sources
, bool track_tests
, bool html
)
1920 module_subset_html_actions actions
;
1921 output_module_subset_report( module
, track_sources
, track_tests
, actions
);
1925 module_subset_txt_actions actions
;
1926 output_module_subset_report( module
, track_sources
, track_tests
, actions
);
1930 // --list-exceptions
1932 static void list_exceptions()
1936 for( std::map
< std::string
, std::set
<std::string
> >::const_iterator i
= s_module_headers
.begin(); i
!= s_module_headers
.end(); ++i
)
1938 std::string module
= i
->first
;
1940 std::replace( module
.begin(), module
.end(), '~', '/' );
1942 std::string
const prefix
= "boost/" + module
;
1943 size_t const n
= prefix
.size();
1945 for( std::set
< std::string
>::const_iterator j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
)
1947 std::string
const & header
= *j
;
1949 if( header
.substr( 0, n
+1 ) != prefix
+ '/' && header
!= prefix
+ ".hpp" )
1953 std::cout
<< module
<< ":\n";
1957 std::cout
<< " " << header
<< '\n';
1965 struct module_test_primary_actions
: public module_primary_actions
1967 std::set
< std::string
> & m_
;
1969 module_test_primary_actions( std::set
< std::string
> & m
): m_( m
)
1973 void heading( std::string
const & module
)
1975 std::cout
<< "Test dependencies for " << module
<< ":\n\n";
1978 void module_start( std::string
const & module
)
1980 std::cout
<< module
<< "\n";
1981 m_
.insert( module
);
1984 void module_end( std::string
const & /*module*/ )
1988 void header_start( std::string
const & /*header*/ )
1992 void header_end( std::string
const & /*header*/ )
1996 void from_header( std::string
const & /*header*/ )
2001 struct module_test_secondary_actions
: public module_secondary_actions
2003 std::set
< std::string
> & m_
;
2006 module_test_secondary_actions( std::set
< std::string
> & m
): m_( m
)
2010 void heading( std::string
const & /*module*/ )
2014 void module_start( std::string
const & module
)
2019 void module_end( std::string
const & /*module*/ )
2023 void module_adds( std::string
const & module
)
2025 if( m_
.count( module
) == 0 )
2027 std::cout
<< module
<< " (from " << m2_
<< ")\n";
2028 m_
.insert( module
);
2033 static void output_module_test_report( std::string
const & module
)
2035 std::set
< std::string
> m
;
2037 module_test_primary_actions
a1( m
);
2038 output_module_primary_report( module
, a1
, true, true );
2042 bool secondary
= false;
2043 enable_secondary( secondary
, true, false );
2045 std::set
< std::string
> m2( m
);
2046 m2
.insert( module
);
2048 module_test_secondary_actions
a2( m2
);
2050 output_module_secondary_report( module
, m
, a2
);
2055 struct collect_primary_dependencies
: public module_primary_actions
2057 std::set
< std::string
> set_
;
2059 void heading( std::string
const & )
2063 void module_start( std::string
const & module
)
2065 if( module
== "(unknown)" ) return;
2067 set_
.insert( module
);
2070 void module_end( std::string
const & /*module*/ )
2074 void header_start( std::string
const & /*header*/ )
2078 void header_end( std::string
const & /*header*/ )
2082 void from_header( std::string
const & /*header*/ )
2087 static std::string
module_cmake_name( std::string module
)
2089 std::replace( module
.begin(), module
.end(), '~', '_' );
2093 static int parse_cxxstd_line( char const* p
)
2095 while( *p
== ' ' || *p
== '\t' ) ++p
;
2097 if( std::strncmp( p
, "\"cxxstd\"", 8 ) != 0 ) return 0;
2100 while( *p
== ' ' || *p
== '\t' ) ++p
;
2102 if( *p
!= ':' ) return 0;
2105 while( *p
== ' ' || *p
== '\t' ) ++p
;
2107 if( p
[0] != '"' ) return 0;
2108 if( p
[1] < '0' || p
[1] > '9' ) return 0;
2109 if( p
[2] < '0' || p
[2] > '9' ) return 0;
2110 if( p
[3] != '"' ) return 0;
2112 int r
= ( p
[1] - '0' ) * 10 + ( p
[2] - '0' );
2114 if( r
< 90 ) r
+= 100;
2119 static int module_cxxstd_requirement( std::string
const& module
)
2121 fs::path lj
= module_meta_path( module
) / "libraries.json";
2125 fs::ifstream
is( lj
);
2129 while( std::getline( is
, line
) )
2131 int r2
= parse_cxxstd_line( line
.c_str() );
2132 if( r2
> r
) r
= r2
;
2138 static void output_module_cmake_report( std::string module
)
2140 int cxxstd
= module_cxxstd_requirement( module
);
2144 "# Generated by `boostdep --cmake " << module
<< "`\n"
2145 "# Copyright 2020, 2021 Peter Dimov\n"
2146 "# Distributed under the Boost Software License, Version 1.0.\n"
2147 "# https://www.boost.org/LICENSE_1_0.txt\n"
2149 "cmake_minimum_required(VERSION " << (cxxstd
>= 111? "3.8": "3.5") << "...3.20)\n"
2153 std::replace( module
.begin(), module
.end(), '/', '~' );
2155 std::vector
<std::string
> sources
;
2156 bool has_c_sources
= false;
2158 fs::path srcpath
= module_source_path( module
);
2160 if( fs::exists( srcpath
) )
2162 fs::directory_iterator
it( srcpath
), last
;
2164 for( ; it
!= last
; ++it
)
2166 if( it
->status().type() != fs::regular_file
) continue;
2168 fs::path p
= it
->path();
2169 std::string ext
= p
.extension().string();
2171 if( ext
!= ".cpp" && ext
!= ".c" ) continue;
2173 std::string name
= p
.filename().string();
2175 sources
.push_back( name
);
2177 if( ext
== ".c" ) has_c_sources
= true;
2181 std::string
lm( module
);
2183 std::replace( lm
.begin(), lm
.end(), '~', '_' );
2187 "project(boost_" << lm
<< " VERSION \"${BOOST_SUPERPROJECT_VERSION}\" LANGUAGES" << ( has_c_sources
? " C": "" ) << " CXX)\n"
2191 collect_primary_dependencies a1
;
2192 output_module_primary_report( module
, a1
, false, false );
2194 if( !fs::exists( srcpath
) )
2196 // header-only library
2200 "add_library(boost_" << lm
<< " INTERFACE)\n"
2201 "add_library(Boost::" << lm
<< " ALIAS boost_" << lm
<< ")\n"
2203 "target_include_directories(boost_" << lm
<< " INTERFACE include)\n"
2207 if( !a1
.set_
.empty() )
2211 "target_link_libraries(boost_" << lm
<< "\n"
2215 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2217 std::cout
<< " Boost::" << module_cmake_name( *i
) << "\n";
2231 "target_compile_features(boost_" << lm
<< " INTERFACE cxx_std_" << cxxstd
- 100 << ")\n"
2242 "add_library(boost_" << lm
<< "\n";
2244 for( std::vector
<std::string
>::iterator i
= sources
.begin(); i
!= sources
.end(); ++i
)
2246 std::cout
<< " src/" << *i
<< "\n";
2253 "add_library(Boost::" << lm
<< " ALIAS boost_" << lm
<< ")\n"
2255 "target_include_directories(boost_" << lm
<< " PUBLIC include)\n"
2259 collect_primary_dependencies a2
;
2260 output_module_primary_report( module
, a2
, true, false );
2262 if( !a1
.set_
.empty() || !a2
.set_
.empty() )
2266 "target_link_libraries(boost_" << lm
<< "\n"
2269 if( !a1
.set_
.empty() )
2276 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2278 a2
.set_
.erase( *i
);
2279 std::cout
<< " Boost::" << module_cmake_name( *i
) << "\n";
2283 if( !a2
.set_
.empty() )
2290 for( std::set
< std::string
>::const_iterator i
= a2
.set_
.begin(); i
!= a2
.set_
.end(); ++i
)
2292 std::cout
<< " Boost::" << module_cmake_name( *i
) << "\n";
2307 "target_compile_features(boost_" << lm
<< " PUBLIC cxx_std_" << cxxstd
- 100 << ")\n"
2312 std::string
um( lm
);
2314 for( std::string::iterator i
= um
.begin(); i
!= um
.end(); ++i
)
2316 *i
= std::toupper( static_cast<unsigned char>( *i
) );
2321 "target_compile_definitions(boost_" << lm
<< "\n"
2322 " PUBLIC BOOST_" << um
<< "_NO_LIB\n"
2323 " PRIVATE BOOST_" << um
<< "_SOURCE\n"
2326 "if(BUILD_SHARED_LIBS)\n"
2327 " target_compile_definitions(boost_" << lm
<< " PUBLIC BOOST_" << um
<< "_DYN_LINK)\n"
2329 " target_compile_definitions(boost_" << lm
<< " PUBLIC BOOST_" << um
<< "_STATIC_LINK)\n"
2337 "if(BUILD_TESTING AND EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt\")\n"
2339 " add_subdirectory(test)\n"
2347 struct module_brief_primary_actions
: public module_primary_actions
2349 std::set
< std::string
> & m_
;
2351 module_brief_primary_actions( std::set
< std::string
> & m
): m_( m
)
2355 void heading( std::string
const & /*module*/ )
2357 std::cout
<< "# Primary dependencies\n\n";
2360 void module_start( std::string
const & module
)
2362 std::cout
<< module
<< "\n";
2363 m_
.insert( module
);
2366 void module_end( std::string
const & /*module*/ )
2370 void header_start( std::string
const & /*header*/ )
2374 void header_end( std::string
const & /*header*/ )
2378 void from_header( std::string
const & /*header*/ )
2383 struct module_brief_secondary_actions
: public module_secondary_actions
2385 std::set
< std::string
> & m_
;
2387 module_brief_secondary_actions( std::set
< std::string
> & m
): m_( m
)
2391 void heading( std::string
const & /*module*/ )
2393 std::cout
<< "# Secondary dependencies\n\n";
2396 void module_start( std::string
const & /*module*/ )
2400 void module_end( std::string
const & /*module*/ )
2404 void module_adds( std::string
const & module
)
2406 if( m_
.count( module
) == 0 )
2408 std::cout
<< module
<< "\n";
2409 m_
.insert( module
);
2414 static void output_module_brief_report( std::string
const & module
, bool track_sources
, bool track_tests
)
2416 std::set
< std::string
> m
;
2418 std::cout
<< "Brief dependency report for " << module
<< " (sources " << (track_sources
? "on": "off") << ", tests " << (track_tests
? "on": "off") << "):\n\n";
2420 module_brief_primary_actions
a1( m
);
2421 output_module_primary_report( module
, a1
, track_sources
, track_tests
);
2425 std::set
< std::string
> m2( m
);
2426 m2
.insert( module
);
2428 module_brief_secondary_actions
a2( m2
);
2429 output_module_secondary_report( module
, m
, a2
);
2432 // --list-missing-headers
2434 struct missing_header_actions
: public module_primary_actions
2436 std::string module_
, module2_
;
2438 void heading( std::string
const & module
)
2443 void module_start( std::string
const & module
)
2448 void module_end( std::string
const & /*module*/ )
2452 void header_start( std::string
const & header
)
2454 if( module2_
== "(unknown)" )
2456 if( !module_
.empty() )
2458 std::cout
<< module_
<< ":\n";
2462 std::cout
<< " <" << header
<< ">\n";
2466 void header_end( std::string
const & /*header*/ )
2470 void from_header( std::string
const & header
)
2472 if( module2_
== "(unknown)" )
2474 std::cout
<< " from <" << header
<< ">\n";
2479 static void list_missing_headers( std::string
const & module
)
2481 missing_header_actions a
;
2482 output_module_primary_report( module
, a
, false, false );
2485 static void list_missing_headers()
2487 for( std::set
< std::string
>::const_iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
2489 list_missing_headers( *i
);
2495 struct primary_pkgconfig_actions
: public module_primary_actions
2497 std::string version_
;
2500 void heading( std::string
const & )
2504 void module_start( std::string
const & module
)
2506 if( module
== "(unknown)" ) return;
2508 std::string
m2( module
);
2509 std::replace( m2
.begin(), m2
.end(), '~', '_' );
2511 if( !list_
.empty() )
2516 list_
+= "boost_" + m2
+ " = " + version_
;
2519 void module_end( std::string
const & )
2523 void header_start( std::string
const & )
2527 void header_end( std::string
const & )
2531 void from_header( std::string
const & )
2536 static void output_requires( std::string
const & section
, std::string
const & version
, std::set
< std::string
> const & s
)
2540 for( std::set
< std::string
>::const_iterator i
= s
.begin(); i
!= s
.end(); ++i
)
2544 std::cout
<< section
<< ": ";
2552 std::string
m2( *i
);
2553 std::replace( m2
.begin(), m2
.end(), '~', '_' );
2555 std::cout
<< "boost_" << m2
<< " = " << version
;
2559 static void output_pkgconfig( std::string
const & module
, std::string
const & version
, int argc
, char const* argv
[] )
2561 for( int i
= 0; i
< argc
; ++i
)
2563 std::cout
<< argv
[ i
] << '\n';
2568 std::string
m2( module
);
2569 std::replace( m2
.begin(), m2
.end(), '/', '_' );
2571 std::string
m3( module
);
2572 std::replace( m3
.begin(), m3
.end(), '/', '~' );
2574 std::cout
<< "Name: boost_" << module
<< '\n';
2575 std::cout
<< "Description: Boost C++ library '" << module
<< "'\n";
2576 std::cout
<< "Version: " << version
<< '\n';
2577 std::cout
<< "URL: http://www.boost.org/libs/" << module
<< '\n';
2578 std::cout
<< "Cflags: -I${includedir}\n";
2580 if( fs::exists( module_build_path( module
) ) && fs::exists( module_source_path( module
) ) )
2582 std::cout
<< "Libs: -L${libdir} -lboost_" << m2
<< "\n";
2585 collect_primary_dependencies a1
;
2586 output_module_primary_report( m3
, a1
, false, false );
2588 if( !a1
.set_
.empty() )
2590 output_requires( "Requires", version
, a1
.set_
);
2591 std::cout
<< std::endl
;
2594 collect_primary_dependencies a2
;
2595 output_module_primary_report( m3
, a2
, true, false );
2597 for( std::set
< std::string
>::const_iterator i
= a1
.set_
.begin(); i
!= a1
.set_
.end(); ++i
)
2599 a2
.set_
.erase( *i
);
2602 if( !a2
.set_
.empty() )
2604 output_requires( "Requires.private", version
, a2
.set_
);
2605 std::cout
<< std::endl
;
2611 static void output_directory_subset_report( std::string
const & module
, std::set
<std::string
> const & headers
, bool html
)
2613 for( std::set
<std::string
>::const_iterator i
= headers
.begin(); i
!= headers
.end(); ++i
)
2615 std::map
< std::string
, std::set
< std::string
> > deps
;
2616 std::map
< std::string
, std::set
< std::string
> > from
;
2618 std::ifstream
is( i
->c_str() );
2619 scan_header_dependencies( *i
, is
, deps
, from
);
2621 for( std::map
< std::string
, std::set
< std::string
> >::const_iterator j
= from
.begin(); j
!= from
.end(); ++j
)
2623 for( std::set
<std::string
>::const_iterator k
= j
->second
.begin(); k
!= j
->second
.end(); ++k
)
2625 s_header_includes
[ *k
].insert( j
->first
);
2632 module_subset_html_actions actions
;
2633 output_module_subset_report_( module
, headers
, actions
);
2637 module_subset_txt_actions actions
;
2638 output_module_subset_report_( module
, headers
, actions
);
2642 // list_buildable_dependencies
2644 struct list_buildable_dependencies_actions
: public module_overview_actions
2646 std::set
< std::string
> buildable_
;
2648 std::set
< std::string
> deps_
;
2651 list_buildable_dependencies_actions(): headers_()
2657 std::cout
<< "# Generated by `boostdep --list-buildable-dependencies`\n\n";
2664 void module_start( std::string
const & module
)
2669 if( buildable_
.count( module
) )
2671 std::cout
<< module
<< " =";
2675 void module_end( std::string
const & module
)
2677 if( buildable_
.count( module
) )
2681 std::cout
<< " headers";
2684 for( std::set
< std::string
>::iterator i
= deps_
.begin(); i
!= deps_
.end(); ++i
)
2686 std::cout
<< " " << *i
;
2689 std::cout
<< " ;\n";
2693 void module2( std::string
const & module
)
2695 if( module
== "(unknown)" ) return;
2697 if( buildable_
.count( module
) == 0 )
2703 deps_
.insert( module
);
2708 static void list_buildable_dependencies()
2710 list_buildable_dependencies_actions actions
;
2712 for( std::set
< std::string
>::iterator i
= s_modules
.begin(); i
!= s_modules
.end(); ++i
)
2714 if( fs::exists( module_build_path( *i
) ) && fs::exists( module_source_path( *i
) ) )
2716 actions
.buildable_
.insert( *i
);
2720 output_module_overview_report( actions
);
2725 static bool find_boost_root()
2727 for( int i
= 0; i
< 32; ++i
)
2729 if( fs::exists( "Jamroot" ) )
2734 fs::path p
= fs::current_path();
2736 if( p
== p
.root_path() )
2741 fs::current_path( p
.parent_path() );
2747 static bool is_boost_root( fs::path
const & p
)
2749 return fs::exists( p
/ "Jamroot" );
2754 class teebuf
: public std::streambuf
2758 std::streambuf
* sb1_
;
2759 std::streambuf
* sb2_
;
2763 teebuf( std::streambuf
* sb1
, std::streambuf
* sb2
): sb1_( sb1
), sb2_( sb2
)
2769 virtual int overflow( int c
)
2771 int r1
= sb1_
->sputc( c
);
2772 int r2
= sb2_
->sputc( c
);
2774 return r1
== EOF
|| r2
== EOF
? EOF
: c
;
2779 int r1
= sb1_
->pubsync();
2780 int r2
= sb2_
->pubsync();
2782 return r1
== 0 && r2
== 0? 0 : -1;
2788 class save_cout_rdbuf
2792 std::streambuf
* sb_
;
2796 save_cout_rdbuf(): sb_( std::cout
.rdbuf() )
2802 std::cout
.rdbuf( sb_
);
2808 int main( int argc
, char const* argv
[] )
2816 " boostdep --list-modules\n"
2817 " boostdep --list-buildable\n"
2818 " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
2819 " boostdep --list-exceptions\n"
2820 " boostdep --list-missing-headers\n"
2821 " boostdep --list-buildable-dependencies\n"
2823 " boostdep [options] --module-overview\n"
2824 " boostdep [options] --module-levels\n"
2825 " boostdep [options] --module-weights\n"
2827 " boostdep [options] [--primary] <module>\n"
2828 " boostdep [options] --secondary <module>\n"
2829 " boostdep [options] --reverse <module>\n"
2830 " boostdep [options] --subset <module>\n"
2831 " boostdep [options] [--header] <header>\n"
2832 " boostdep --test <module>\n"
2833 " boostdep --cmake <module>\n"
2834 " boostdep --pkgconfig <module> <version> [<var>=<value>] [<var>=<value>]...\n"
2835 " boostdep [options] --subset-for <directory>\n"
2836 " boostdep --brief <module>\n"
2838 " [options]: [--boost-root <path-to-boost>]\n"
2839 " [--[no-]track-sources] [--[no-]track-tests]\n"
2840 " [--html-title <title>] [--html-footer <footer>]\n"
2841 " [--html-stylesheet <stylesheet>] [--html-prefix <prefix>]\n"
2847 bool root_set
= false;
2849 for( int i
= 0; i
< argc
; ++i
)
2851 std::string option
= argv
[ i
];
2853 if( option
== "--boost-root" )
2857 fs::path
p( argv
[ ++i
] );
2859 if( is_boost_root( p
) )
2861 fs::current_path( p
);
2866 std::cerr
<< "'" << p
.string() << "': not a valid Boost root.\n";
2872 std::cerr
<< "'" << option
<< "': missing argument.\n";
2878 if( !root_set
&& !find_boost_root() )
2880 char const * env_root
= std::getenv( "BOOST_ROOT" );
2882 if( env_root
&& is_boost_root( env_root
) )
2884 fs::current_path( env_root
);
2888 std::cerr
<< "boostdep: Could not find Boost root.\n";
2897 catch( fs::filesystem_error
const & x
)
2899 std::cerr
<< x
.what() << std::endl
;
2903 bool secondary
= false;
2904 bool track_sources
= true;
2905 bool track_tests
= false;
2907 std::string html_title
= "Boost Dependency Report";
2908 std::string html_footer
;
2909 std::string html_stylesheet
;
2910 std::string html_prefix
;
2912 std::ostringstream captured_output
;
2913 teebuf
tsb( std::cout
.rdbuf(), captured_output
.rdbuf() );
2915 save_cout_rdbuf scrdb
;
2917 for( int i
= 1; i
< argc
; ++i
)
2919 std::string option
= argv
[ i
];
2921 if( option
== "--boost-root" )
2925 else if( option
== "--list-modules" )
2929 else if( option
== "--list-buildable" )
2933 else if( option
== "--title" || option
== "--html-title" )
2937 html_title
= argv
[ ++i
];
2940 else if( option
== "--footer" || option
== "--html-footer" )
2944 html_footer
= argv
[ ++i
];
2947 else if( option
== "--html-stylesheet" )
2951 html_stylesheet
= argv
[ ++i
];
2954 else if( option
== "--html-prefix" )
2958 html_prefix
= argv
[ ++i
];
2961 else if( option
== "--html" )
2966 output_html_header( html_title
, html_stylesheet
, html_prefix
);
2969 else if( option
== "--track-sources" )
2971 track_sources
= true;
2973 else if( option
== "--no-track-sources" )
2975 track_sources
= false;
2977 else if( option
== "--track-tests" )
2981 else if( option
== "--no-track-tests" )
2983 track_tests
= false;
2985 else if( option
== "--primary" )
2989 output_module_primary_report( argv
[ ++i
], html
, track_sources
, track_tests
);
2992 else if( option
== "--secondary" )
2996 enable_secondary( secondary
, track_sources
, track_tests
);
2997 output_module_secondary_report( argv
[ ++i
], html
);
3000 else if( option
== "--reverse" )
3004 enable_secondary( secondary
, track_sources
, track_tests
);
3005 output_module_reverse_report( argv
[ ++i
], html
);
3008 else if( option
== "--header" )
3012 enable_secondary( secondary
, track_sources
, track_tests
);
3013 output_header_report( argv
[ ++i
], html
);
3016 else if( option
== "--subset" )
3020 enable_secondary( secondary
, track_sources
, track_tests
);
3021 output_module_subset_report( argv
[ ++i
], track_sources
, track_tests
, html
);
3024 else if( option
== "--test" )
3028 output_module_test_report( argv
[ ++i
] );
3031 else if( option
== "--cmake" )
3035 output_module_cmake_report( argv
[ ++i
] );
3038 else if( option
== "--brief" )
3042 enable_secondary( secondary
, track_sources
, track_tests
);
3043 output_module_brief_report( argv
[ ++i
], track_sources
, track_tests
);
3046 else if( option
== "--module-levels" )
3048 enable_secondary( secondary
, track_sources
, track_tests
);
3049 output_module_level_report( html
);
3051 else if( option
== "--module-overview" )
3053 enable_secondary( secondary
, track_sources
, track_tests
);
3054 output_module_overview_report( html
);
3056 else if( option
== "--module-weights" )
3058 enable_secondary( secondary
, track_sources
, track_tests
);
3059 output_module_weight_report( html
);
3061 else if( option
== "--list-dependencies" )
3063 enable_secondary( secondary
, track_sources
, track_tests
);
3064 list_dependencies();
3066 else if( option
== "--list-exceptions" )
3070 else if( option
== "--list-missing-headers" )
3072 list_missing_headers();
3074 else if( option
== "--pkgconfig" )
3078 std::string module
= argv
[ ++i
];
3079 std::string version
= argv
[ ++i
];
3083 output_pkgconfig( module
, version
, argc
- i
, argv
+ i
);
3087 std::cerr
<< "'" << option
<< "': missing module or version.\n";
3092 else if( option
== "--subset-for" )
3096 std::string module
= argv
[ ++i
];
3098 enable_secondary( secondary
, track_sources
, track_tests
);
3100 std::set
<std::string
> headers
;
3101 add_module_headers( module
, headers
);
3103 output_directory_subset_report( module
, headers
, html
);
3107 std::cerr
<< "'" << option
<< "': missing argument.\n";
3112 else if( option
== "--list-buildable-dependencies" )
3114 enable_secondary( secondary
, true, false );
3115 list_buildable_dependencies();
3117 else if( option
== "--capture-output" )
3119 std::cout
.rdbuf( &tsb
);
3121 else if( option
== "--compare-output" )
3125 std::string fn
= argv
[ ++i
];
3126 std::fstream
is( fn
.c_str() );
3130 std::cerr
<< option
<< " '" << fn
<< "': could not open file.\n";
3134 std::istreambuf_iterator
<char> first( is
), last
;
3135 std::string
fc( first
, last
);
3137 if( fc
!= captured_output
.str() )
3139 std::cerr
<< option
<< " '" << fn
<< "': output does not match; expected output:\n---\n" << fc
<< "---\n";
3143 std::cerr
<< option
<< " '" << fn
<< "': output matches.\n";
3144 captured_output
.str( "" );
3148 std::cerr
<< "'" << option
<< "': missing argument.\n";
3152 else if( s_modules
.count( option
) )
3154 output_module_primary_report( option
, html
, track_sources
, track_tests
);
3156 else if( s_header_map
.count( option
) )
3158 enable_secondary( secondary
, track_sources
, track_tests
);
3159 output_header_report( option
, html
);
3163 std::cerr
<< "'" << option
<< "': not an option, module or header.\n";
3169 output_html_footer( html_footer
);