summaryrefslogtreecommitdiffstats
path: root/src/boost/tools/boostdep
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/boost/tools/boostdep/CMakeLists.txt15
-rw-r--r--src/boost/tools/boostdep/README.md4
-rw-r--r--src/boost/tools/boostdep/build/Jamfile11
-rw-r--r--src/boost/tools/boostdep/depinst/depinst.py282
-rw-r--r--src/boost/tools/boostdep/depinst/exceptions.txt396
-rw-r--r--src/boost/tools/boostdep/examples/report.bat39
-rw-r--r--src/boost/tools/boostdep/examples/report.css24
-rw-r--r--src/boost/tools/boostdep/src/boostdep.cpp3005
-rw-r--r--src/boost/tools/boostdep/test/Jamfile12
-rw-r--r--src/boost/tools/boostdep/test/assert-primary.txt9
-rw-r--r--src/boost/tools/boostdep/test/bind-secondary.txt5
-rw-r--r--src/boost/tools/boostdep/test/utf8-test.zipbin0 -> 495 bytes
12 files changed, 3802 insertions, 0 deletions
diff --git a/src/boost/tools/boostdep/CMakeLists.txt b/src/boost/tools/boostdep/CMakeLists.txt
new file mode 100644
index 000000000..0bc583477
--- /dev/null
+++ b/src/boost/tools/boostdep/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright 2018 Mike Dev
+# Copyright 2018 Peter Dimov
+# Distributed under the Boost Software License, Version 1.0.
+# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
+
+cmake_minimum_required( VERSION 3.1 )
+
+project( boostdep LANGUAGES CXX )
+
+add_executable( boostdep src/boostdep.cpp )
+
+find_package( Boost COMPONENTS filesystem REQUIRED )
+target_link_libraries( boostdep Boost::filesystem )
+
+install( TARGETS boostdep RUNTIME DESTINATION bin )
diff --git a/src/boost/tools/boostdep/README.md b/src/boost/tools/boostdep/README.md
new file mode 100644
index 000000000..ff87dfb85
--- /dev/null
+++ b/src/boost/tools/boostdep/README.md
@@ -0,0 +1,4 @@
+boostdep
+========
+
+A tool to create Boost module dependency reports
diff --git a/src/boost/tools/boostdep/build/Jamfile b/src/boost/tools/boostdep/build/Jamfile
new file mode 100644
index 000000000..2e0491bee
--- /dev/null
+++ b/src/boost/tools/boostdep/build/Jamfile
@@ -0,0 +1,11 @@
+# Copyright 2014, 2015 Peter Dimov
+#
+# Distributed under the Boost Software License, Version 1.0.
+# See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt
+
+project : default-build release ;
+
+exe boostdep : ../src/boostdep.cpp /boost//filesystem ;
+
+install dist-bin : boostdep : <location>../../../dist/bin ;
diff --git a/src/boost/tools/boostdep/depinst/depinst.py b/src/boost/tools/boostdep/depinst/depinst.py
new file mode 100644
index 000000000..6dfba36a7
--- /dev/null
+++ b/src/boost/tools/boostdep/depinst/depinst.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python
+
+# depinst.py - installs the dependencies needed to test
+# a Boost library
+#
+# Copyright 2016-2020 Peter Dimov
+#
+# Distributed under the Boost Software License, Version 1.0.
+# See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt
+
+from __future__ import print_function
+
+import re
+import sys
+import os
+import argparse
+
+verbose = 0
+
+def vprint( level, *args ):
+
+ if verbose >= level:
+ print( *args )
+
+
+def is_module( m, gm ):
+
+ return ( 'libs/' + m ) in gm
+
+
+def module_for_header( h, x, gm ):
+
+ if h in x:
+
+ return x[ h ]
+
+ else:
+
+ # boost/function.hpp
+ m = re.match( 'boost/([^\\./]*)\\.h[a-z]*$', h )
+
+ if m and is_module( m.group( 1 ), gm ):
+
+ return m.group( 1 )
+
+ # boost/numeric/conversion.hpp
+ m = re.match( 'boost/([^/]*/[^\\./]*)\\.h[a-z]*$', h )
+
+ if m and is_module( m.group( 1 ), gm ):
+
+ return m.group( 1 )
+
+ # boost/numeric/conversion/header.hpp
+ m = re.match( 'boost/([^/]*/[^/]*)/', h )
+
+ if m and is_module( m.group( 1 ), gm ):
+
+ return m.group( 1 )
+
+ # boost/function/header.hpp
+ m = re.match( 'boost/([^/]*)/', h )
+
+ if m and is_module( m.group( 1 ), gm ):
+
+ return m.group( 1 )
+
+ vprint( 0, 'Cannot determine module for header', h )
+
+ return None
+
+
+def scan_header_dependencies( f, x, gm, deps ):
+
+ for line in f:
+
+ m = re.match( '[ \t]*#[ \t]*include[ \t]*["<](boost/[^">]*)[">]', line )
+
+ if m:
+
+ h = m.group( 1 )
+
+ mod = module_for_header( h, x, gm )
+
+ if mod:
+
+ if not mod in deps:
+
+ vprint( 1, 'Adding dependency', mod )
+ deps[ mod ] = 0
+
+
+def scan_directory( d, x, gm, deps ):
+
+ vprint( 1, 'Scanning directory', d )
+
+ if os.name == 'nt' and sys.version_info[0] < 3:
+ d = unicode( d )
+
+ for root, dirs, files in os.walk( d ):
+
+ for file in files:
+
+ fn = os.path.join( root, file )
+
+ vprint( 2, 'Scanning file', fn )
+
+ if sys.version_info[0] < 3:
+
+ with open( fn, 'r' ) as f:
+ scan_header_dependencies( f, x, gm, deps )
+
+ else:
+
+ with open( fn, 'r', encoding='latin-1' ) as f:
+ scan_header_dependencies( f, x, gm, deps )
+
+
+def scan_module_dependencies( m, x, gm, deps, dirs ):
+
+ vprint( 1, 'Scanning module', m )
+
+ for dir in dirs:
+ scan_directory( os.path.join( 'libs', m, dir ), x, gm, deps )
+
+
+def read_exceptions():
+
+ # exceptions.txt is the output of "boostdep --list-exceptions"
+
+ vprint( 1, 'Reading exceptions.txt' )
+
+ x = {}
+
+ module = None
+
+ with open( os.path.join( os.path.dirname( sys.argv[0] ), 'exceptions.txt' ), 'r' ) as f:
+
+ for line in f:
+
+ line = line.rstrip()
+
+ m = re.match( '(.*):$', line )
+
+ if m:
+
+ module = m.group( 1 ).replace( '~', '/' )
+
+ else:
+
+ header = line.lstrip()
+ x[ header ] = module
+
+ return x
+
+
+def read_gitmodules():
+
+ vprint( 1, 'Reading .gitmodules' )
+
+ gm = []
+
+ with open( '.gitmodules', 'r' ) as f:
+
+ for line in f:
+
+ line = line.strip()
+
+ m = re.match( 'path[ \t]*=[ \t]*(.*)$', line )
+
+ if m:
+
+ gm.append( m.group( 1 ) )
+
+ return gm
+
+def install_modules( modules, git_args ):
+
+ if len( modules ) == 0:
+ return
+
+ vprint( 0, 'Installing:', ', '.join(modules) )
+
+ modules = [ 'libs/' + m for m in modules ]
+
+ command = 'git submodule'
+
+ if verbose <= 0:
+ command += ' -q'
+
+ command += ' update --init ' + git_args + ' ' + ' '.join( modules )
+
+ vprint( 1, 'Executing:', command )
+ r = os.system( command );
+
+ if r != 0:
+ raise Exception( "The command '%s' failed with exit code %d" % (command, r) )
+
+
+def install_module_dependencies( deps, x, gm, git_args ):
+
+ modules = []
+
+ for m, i in deps.items():
+
+ if not i:
+
+ modules += [ m ]
+ deps[ m ] = 1 # mark as installed
+
+ if len( modules ) == 0:
+ return 0
+
+ install_modules( modules, git_args )
+
+ for m in modules:
+ scan_module_dependencies( m, x, gm, deps, [ 'include', 'src' ] )
+
+ return len( modules )
+
+
+if( __name__ == "__main__" ):
+
+ parser = argparse.ArgumentParser( description='Installs the dependencies needed to test a Boost library.' )
+
+ parser.add_argument( '-v', '--verbose', help='enable verbose output', action='count', default=0 )
+ parser.add_argument( '-q', '--quiet', help='quiet output (opposite of -v)', action='count', default=0 )
+ parser.add_argument( '-X', '--exclude', help="exclude a default subdirectory ('include', 'src', or 'test') from scan; can be repeated", metavar='DIR', action='append', default=[] )
+ parser.add_argument( '-N', '--ignore', help="exclude top-level dependency even when found in scan; can be repeated", metavar='LIB', action='append', default=[] )
+ parser.add_argument( '-I', '--include', help="additional subdirectory to scan; can be repeated", metavar='DIR', action='append', default=[] )
+ parser.add_argument( '-g', '--git_args', help="additional arguments to `git submodule update`", default='', action='store' )
+ parser.add_argument( '-u', '--update', help='update <library> before scanning', action='store_true' )
+ parser.add_argument( 'library', help="name of library to scan ('libs/' will be prepended)" )
+
+ args = parser.parse_args()
+
+ verbose = args.verbose - args.quiet
+
+ vprint( 2, '-X:', args.exclude )
+ vprint( 2, '-I:', args.include )
+ vprint( 2, '-N:', args.ignore )
+
+ x = read_exceptions()
+ vprint( 2, 'Exceptions:', x )
+
+ gm = read_gitmodules()
+ vprint( 2, '.gitmodules:', gm )
+
+ essentials = [ 'config', 'headers', '../tools/boost_install', '../tools/build', '../tools/cmake' ]
+
+ essentials = [ e for e in essentials if os.path.exists( 'libs/' + e ) ]
+
+ if args.update:
+ essentials.append( args.library )
+
+ install_modules( essentials, args.git_args )
+
+ m = args.library
+
+ deps = { m : 1 }
+
+ dirs = [ 'include', 'src', 'test' ]
+
+ for dir in args.exclude:
+ dirs.remove( dir )
+
+ for dir in args.include:
+ dirs.append( dir )
+
+ vprint( 1, 'Directories to scan:', *dirs )
+
+ scan_module_dependencies( m, x, gm, deps, dirs )
+
+ for dep in args.ignore:
+ if dep in deps:
+ vprint( 1, 'Ignoring dependency', dep )
+ del deps[dep]
+
+ vprint( 2, 'Dependencies:', deps )
+
+ while install_module_dependencies( deps, x, gm, args.git_args ):
+ pass
diff --git a/src/boost/tools/boostdep/depinst/exceptions.txt b/src/boost/tools/boostdep/depinst/exceptions.txt
new file mode 100644
index 000000000..d5b540260
--- /dev/null
+++ b/src/boost/tools/boostdep/depinst/exceptions.txt
@@ -0,0 +1,396 @@
+assert:
+ boost/current_function.hpp
+atomic:
+ boost/memory_order.hpp
+bind:
+ boost/is_placeholder.hpp
+ boost/mem_fn.hpp
+circular_buffer:
+ boost/circular_buffer_fwd.hpp
+concept_check:
+ boost/concept/assert.hpp
+ boost/concept/detail/backward_compatibility.hpp
+ boost/concept/detail/borland.hpp
+ boost/concept/detail/concept_def.hpp
+ boost/concept/detail/concept_undef.hpp
+ boost/concept/detail/general.hpp
+ boost/concept/detail/has_constraints.hpp
+ boost/concept/detail/msvc.hpp
+ boost/concept/requires.hpp
+ boost/concept/usage.hpp
+ boost/concept_archetype.hpp
+config:
+ boost/cstdint.hpp
+ boost/cxx11_char_types.hpp
+ boost/detail/workaround.hpp
+ boost/limits.hpp
+ boost/version.hpp
+container_hash:
+ boost/functional/hash.hpp
+ boost/functional/hash/extensions.hpp
+ boost/functional/hash/hash.hpp
+ boost/functional/hash/hash_fwd.hpp
+ boost/functional/hash_fwd.hpp
+contract:
+ boost/contract_macro.hpp
+conversion:
+ boost/implicit_cast.hpp
+ boost/polymorphic_cast.hpp
+ boost/polymorphic_pointer_cast.hpp
+convert:
+ boost/make_default.hpp
+core:
+ boost/checked_delete.hpp
+ boost/detail/iterator.hpp
+ boost/detail/lightweight_test.hpp
+ boost/detail/no_exceptions_support.hpp
+ boost/detail/scoped_enum_emulation.hpp
+ boost/detail/sp_typeinfo.hpp
+ boost/get_pointer.hpp
+ boost/iterator.hpp
+ boost/non_type.hpp
+ boost/noncopyable.hpp
+ boost/ref.hpp
+ boost/swap.hpp
+ boost/type.hpp
+ boost/utility/addressof.hpp
+ boost/utility/enable_if.hpp
+ boost/utility/explicit_operator_bool.hpp
+ boost/utility/swap.hpp
+ boost/visit_each.hpp
+detail:
+ boost/blank.hpp
+ boost/blank_fwd.hpp
+ boost/cstdlib.hpp
+dynamic_bitset:
+ boost/dynamic_bitset_fwd.hpp
+exception:
+ boost/exception_ptr.hpp
+foreach:
+ boost/foreach_fwd.hpp
+function:
+ boost/function_equal.hpp
+graph:
+ boost/detail/algorithm.hpp
+ boost/pending/bucket_sorter.hpp
+ boost/pending/container_traits.hpp
+ boost/pending/detail/disjoint_sets.hpp
+ boost/pending/detail/property.hpp
+ boost/pending/disjoint_sets.hpp
+ boost/pending/fenced_priority_queue.hpp
+ boost/pending/fibonacci_heap.hpp
+ boost/pending/indirect_cmp.hpp
+ boost/pending/is_heap.hpp
+ boost/pending/mutable_heap.hpp
+ boost/pending/mutable_queue.hpp
+ boost/pending/property.hpp
+ boost/pending/property_serialize.hpp
+ boost/pending/queue.hpp
+ boost/pending/relaxed_heap.hpp
+ boost/pending/stringtok.hpp
+graph_parallel:
+ boost/graph/accounting.hpp
+ boost/graph/distributed/adjacency_list.hpp
+ boost/graph/distributed/adjlist/handlers.hpp
+ boost/graph/distributed/adjlist/initialize.hpp
+ boost/graph/distributed/adjlist/redistribute.hpp
+ boost/graph/distributed/adjlist/serialization.hpp
+ boost/graph/distributed/betweenness_centrality.hpp
+ boost/graph/distributed/boman_et_al_graph_coloring.hpp
+ boost/graph/distributed/breadth_first_search.hpp
+ boost/graph/distributed/compressed_sparse_row_graph.hpp
+ boost/graph/distributed/concepts.hpp
+ boost/graph/distributed/connected_components.hpp
+ boost/graph/distributed/connected_components_parallel_search.hpp
+ boost/graph/distributed/crauser_et_al_shortest_paths.hpp
+ boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp
+ boost/graph/distributed/delta_stepping_shortest_paths.hpp
+ boost/graph/distributed/depth_first_search.hpp
+ boost/graph/distributed/detail/dijkstra_shortest_paths.hpp
+ boost/graph/distributed/detail/filtered_queue.hpp
+ boost/graph/distributed/detail/mpi_process_group.ipp
+ boost/graph/distributed/detail/queue.ipp
+ boost/graph/distributed/detail/remote_update_set.hpp
+ boost/graph/distributed/detail/tag_allocator.hpp
+ boost/graph/distributed/dijkstra_shortest_paths.hpp
+ boost/graph/distributed/distributed_graph_utility.hpp
+ boost/graph/distributed/eager_dijkstra_shortest_paths.hpp
+ boost/graph/distributed/filtered_graph.hpp
+ boost/graph/distributed/fruchterman_reingold.hpp
+ boost/graph/distributed/graphviz.hpp
+ boost/graph/distributed/hohberg_biconnected_components.hpp
+ boost/graph/distributed/local_subgraph.hpp
+ boost/graph/distributed/mpi_process_group.hpp
+ boost/graph/distributed/named_graph.hpp
+ boost/graph/distributed/one_bit_color_map.hpp
+ boost/graph/distributed/page_rank.hpp
+ boost/graph/distributed/queue.hpp
+ boost/graph/distributed/reverse_graph.hpp
+ boost/graph/distributed/rmat_graph_generator.hpp
+ boost/graph/distributed/selector.hpp
+ boost/graph/distributed/shuffled_distribution.hpp
+ boost/graph/distributed/st_connected.hpp
+ boost/graph/distributed/strong_components.hpp
+ boost/graph/distributed/two_bit_color_map.hpp
+ boost/graph/distributed/unsafe_serialize.hpp
+ boost/graph/distributed/vertex_list_adaptor.hpp
+ boost/graph/parallel/algorithm.hpp
+ boost/graph/parallel/basic_reduce.hpp
+ boost/graph/parallel/container_traits.hpp
+ boost/graph/parallel/detail/inplace_all_to_all.hpp
+ boost/graph/parallel/detail/property_holders.hpp
+ boost/graph/parallel/detail/untracked_pair.hpp
+ boost/graph/parallel/distribution.hpp
+ boost/graph/parallel/process_group.hpp
+ boost/graph/parallel/properties.hpp
+ boost/graph/parallel/simple_trigger.hpp
+integer:
+ boost/integer_fwd.hpp
+ boost/integer_traits.hpp
+ boost/pending/integer_log2.hpp
+io:
+ boost/io_fwd.hpp
+iterator:
+ boost/function_output_iterator.hpp
+ boost/generator_iterator.hpp
+ boost/indirect_reference.hpp
+ boost/iterator_adaptors.hpp
+ boost/next_prior.hpp
+ boost/pending/detail/int_iterator.hpp
+ boost/pending/iterator_adaptors.hpp
+ boost/pending/iterator_tests.hpp
+ boost/pointee.hpp
+ boost/shared_container_iterator.hpp
+lexical_cast:
+ boost/detail/basic_pointerbuf.hpp
+ boost/detail/lcast_precision.hpp
+math:
+ boost/cstdfloat.hpp
+ boost/math_fwd.hpp
+multi_index:
+ boost/multi_index_container.hpp
+ boost/multi_index_container_fwd.hpp
+numeric/conversion:
+ boost/cast.hpp
+optional:
+ boost/none.hpp
+ boost/none_t.hpp
+parameter_python:
+ boost/parameter/aux_/python/invoker.hpp
+ boost/parameter/aux_/python/invoker_iterate.hpp
+ boost/parameter/python.hpp
+predef:
+ boost/predef.h
+random:
+ boost/nondet_random.hpp
+regex:
+ boost/cregex.hpp
+ boost/regex.h
+ boost/regex_fwd.hpp
+serialization:
+ boost/archive/archive_exception.hpp
+ boost/archive/basic_archive.hpp
+ boost/archive/basic_binary_iarchive.hpp
+ boost/archive/basic_binary_iprimitive.hpp
+ boost/archive/basic_binary_oarchive.hpp
+ boost/archive/basic_binary_oprimitive.hpp
+ boost/archive/basic_streambuf_locale_saver.hpp
+ boost/archive/basic_text_iarchive.hpp
+ boost/archive/basic_text_iprimitive.hpp
+ boost/archive/basic_text_oarchive.hpp
+ boost/archive/basic_text_oprimitive.hpp
+ boost/archive/basic_xml_archive.hpp
+ boost/archive/basic_xml_iarchive.hpp
+ boost/archive/basic_xml_oarchive.hpp
+ boost/archive/binary_iarchive.hpp
+ boost/archive/binary_iarchive_impl.hpp
+ boost/archive/binary_oarchive.hpp
+ boost/archive/binary_oarchive_impl.hpp
+ boost/archive/binary_wiarchive.hpp
+ boost/archive/binary_woarchive.hpp
+ boost/archive/codecvt_null.hpp
+ boost/archive/detail/abi_prefix.hpp
+ boost/archive/detail/abi_suffix.hpp
+ boost/archive/detail/archive_serializer_map.hpp
+ boost/archive/detail/auto_link_archive.hpp
+ boost/archive/detail/auto_link_warchive.hpp
+ boost/archive/detail/basic_iarchive.hpp
+ boost/archive/detail/basic_iserializer.hpp
+ boost/archive/detail/basic_oarchive.hpp
+ boost/archive/detail/basic_oserializer.hpp
+ boost/archive/detail/basic_pointer_iserializer.hpp
+ boost/archive/detail/basic_pointer_oserializer.hpp
+ boost/archive/detail/basic_serializer.hpp
+ boost/archive/detail/basic_serializer_map.hpp
+ boost/archive/detail/check.hpp
+ boost/archive/detail/common_iarchive.hpp
+ boost/archive/detail/common_oarchive.hpp
+ boost/archive/detail/decl.hpp
+ boost/archive/detail/helper_collection.hpp
+ boost/archive/detail/interface_iarchive.hpp
+ boost/archive/detail/interface_oarchive.hpp
+ boost/archive/detail/iserializer.hpp
+ boost/archive/detail/oserializer.hpp
+ boost/archive/detail/polymorphic_iarchive_route.hpp
+ boost/archive/detail/polymorphic_oarchive_route.hpp
+ boost/archive/detail/register_archive.hpp
+ boost/archive/detail/utf8_codecvt_facet.hpp
+ boost/archive/dinkumware.hpp
+ boost/archive/impl/archive_serializer_map.ipp
+ boost/archive/impl/basic_binary_iarchive.ipp
+ boost/archive/impl/basic_binary_iprimitive.ipp
+ boost/archive/impl/basic_binary_oarchive.ipp
+ boost/archive/impl/basic_binary_oprimitive.ipp
+ boost/archive/impl/basic_text_iarchive.ipp
+ boost/archive/impl/basic_text_iprimitive.ipp
+ boost/archive/impl/basic_text_oarchive.ipp
+ boost/archive/impl/basic_text_oprimitive.ipp
+ boost/archive/impl/basic_xml_grammar.hpp
+ boost/archive/impl/basic_xml_iarchive.ipp
+ boost/archive/impl/basic_xml_oarchive.ipp
+ boost/archive/impl/text_iarchive_impl.ipp
+ boost/archive/impl/text_oarchive_impl.ipp
+ boost/archive/impl/text_wiarchive_impl.ipp
+ boost/archive/impl/text_woarchive_impl.ipp
+ boost/archive/impl/xml_iarchive_impl.ipp
+ boost/archive/impl/xml_oarchive_impl.ipp
+ boost/archive/impl/xml_wiarchive_impl.ipp
+ boost/archive/impl/xml_woarchive_impl.ipp
+ boost/archive/iterators/base64_exception.hpp
+ boost/archive/iterators/base64_from_binary.hpp
+ boost/archive/iterators/binary_from_base64.hpp
+ boost/archive/iterators/dataflow.hpp
+ boost/archive/iterators/dataflow_exception.hpp
+ boost/archive/iterators/escape.hpp
+ boost/archive/iterators/insert_linebreaks.hpp
+ boost/archive/iterators/istream_iterator.hpp
+ boost/archive/iterators/mb_from_wchar.hpp
+ boost/archive/iterators/ostream_iterator.hpp
+ boost/archive/iterators/remove_whitespace.hpp
+ boost/archive/iterators/transform_width.hpp
+ boost/archive/iterators/unescape.hpp
+ boost/archive/iterators/wchar_from_mb.hpp
+ boost/archive/iterators/xml_escape.hpp
+ boost/archive/iterators/xml_unescape.hpp
+ boost/archive/iterators/xml_unescape_exception.hpp
+ boost/archive/polymorphic_binary_iarchive.hpp
+ boost/archive/polymorphic_binary_oarchive.hpp
+ boost/archive/polymorphic_iarchive.hpp
+ boost/archive/polymorphic_oarchive.hpp
+ boost/archive/polymorphic_text_iarchive.hpp
+ boost/archive/polymorphic_text_oarchive.hpp
+ boost/archive/polymorphic_text_wiarchive.hpp
+ boost/archive/polymorphic_text_woarchive.hpp
+ boost/archive/polymorphic_xml_iarchive.hpp
+ boost/archive/polymorphic_xml_oarchive.hpp
+ boost/archive/polymorphic_xml_wiarchive.hpp
+ boost/archive/polymorphic_xml_woarchive.hpp
+ boost/archive/text_iarchive.hpp
+ boost/archive/text_oarchive.hpp
+ boost/archive/text_wiarchive.hpp
+ boost/archive/text_woarchive.hpp
+ boost/archive/tmpdir.hpp
+ boost/archive/wcslen.hpp
+ boost/archive/xml_archive_exception.hpp
+ boost/archive/xml_iarchive.hpp
+ boost/archive/xml_oarchive.hpp
+ boost/archive/xml_wiarchive.hpp
+ boost/archive/xml_woarchive.hpp
+smart_ptr:
+ boost/detail/atomic_count.hpp
+ boost/detail/lightweight_mutex.hpp
+ boost/detail/lightweight_thread.hpp
+ boost/detail/quick_allocator.hpp
+ boost/enable_shared_from_this.hpp
+ boost/intrusive_ptr.hpp
+ boost/make_shared.hpp
+ boost/make_unique.hpp
+ boost/pointer_cast.hpp
+ boost/pointer_to_other.hpp
+ boost/scoped_array.hpp
+ boost/scoped_ptr.hpp
+ boost/shared_array.hpp
+ boost/shared_ptr.hpp
+ boost/weak_ptr.hpp
+system:
+ boost/cerrno.hpp
+throw_exception:
+ boost/exception/exception.hpp
+timer:
+ boost/progress.hpp
+tokenizer:
+ boost/token_functions.hpp
+ boost/token_iterator.hpp
+type_traits:
+ boost/aligned_storage.hpp
+ boost/utility/declval.hpp
+unordered:
+ boost/unordered_map.hpp
+ boost/unordered_set.hpp
+utility:
+ boost/call_traits.hpp
+ boost/compressed_pair.hpp
+ boost/detail/call_traits.hpp
+ boost/detail/compressed_pair.hpp
+ boost/detail/ob_compressed_pair.hpp
+ boost/operators.hpp
+ boost/operators_v1.hpp
+winapi:
+ boost/detail/interlocked.hpp
+ boost/detail/winapi/access_rights.hpp
+ boost/detail/winapi/apc.hpp
+ boost/detail/winapi/basic_types.hpp
+ boost/detail/winapi/bcrypt.hpp
+ boost/detail/winapi/character_code_conversion.hpp
+ boost/detail/winapi/condition_variable.hpp
+ boost/detail/winapi/config.hpp
+ boost/detail/winapi/critical_section.hpp
+ boost/detail/winapi/crypt.hpp
+ boost/detail/winapi/dbghelp.hpp
+ boost/detail/winapi/debugapi.hpp
+ boost/detail/winapi/detail/deprecated_namespace.hpp
+ boost/detail/winapi/directory_management.hpp
+ boost/detail/winapi/dll.hpp
+ boost/detail/winapi/environment.hpp
+ boost/detail/winapi/error_codes.hpp
+ boost/detail/winapi/error_handling.hpp
+ boost/detail/winapi/event.hpp
+ boost/detail/winapi/file_management.hpp
+ boost/detail/winapi/file_mapping.hpp
+ boost/detail/winapi/get_current_process.hpp
+ boost/detail/winapi/get_current_process_id.hpp
+ boost/detail/winapi/get_current_thread.hpp
+ boost/detail/winapi/get_current_thread_id.hpp
+ boost/detail/winapi/get_last_error.hpp
+ boost/detail/winapi/get_process_times.hpp
+ boost/detail/winapi/get_system_directory.hpp
+ boost/detail/winapi/get_thread_times.hpp
+ boost/detail/winapi/handle_info.hpp
+ boost/detail/winapi/handles.hpp
+ boost/detail/winapi/heap_memory.hpp
+ boost/detail/winapi/init_once.hpp
+ boost/detail/winapi/jobs.hpp
+ boost/detail/winapi/limits.hpp
+ boost/detail/winapi/local_memory.hpp
+ boost/detail/winapi/memory.hpp
+ boost/detail/winapi/mutex.hpp
+ boost/detail/winapi/overlapped.hpp
+ boost/detail/winapi/page_protection_flags.hpp
+ boost/detail/winapi/pipes.hpp
+ boost/detail/winapi/priority_class.hpp
+ boost/detail/winapi/process.hpp
+ boost/detail/winapi/security.hpp
+ boost/detail/winapi/semaphore.hpp
+ boost/detail/winapi/shell.hpp
+ boost/detail/winapi/show_window.hpp
+ boost/detail/winapi/srw_lock.hpp
+ boost/detail/winapi/stack_backtrace.hpp
+ boost/detail/winapi/synchronization.hpp
+ boost/detail/winapi/system.hpp
+ boost/detail/winapi/thread.hpp
+ boost/detail/winapi/thread_pool.hpp
+ boost/detail/winapi/time.hpp
+ boost/detail/winapi/timers.hpp
+ boost/detail/winapi/tls.hpp
+ boost/detail/winapi/wait.hpp
+ boost/detail/winapi/waitable_timer.hpp
diff --git a/src/boost/tools/boostdep/examples/report.bat b/src/boost/tools/boostdep/examples/report.bat
new file mode 100644
index 000000000..c244177ed
--- /dev/null
+++ b/src/boost/tools/boostdep/examples/report.bat
@@ -0,0 +1,39 @@
+@REM This is an example cmd.exe batch script
+@REM that uses boostdep.exe to generate a
+@REM complete Boost dependency report.
+@REM
+@REM It needs to be run from the Boost root.
+@REM
+@REM Copyright 2014, 2015, 2017 Peter Dimov
+@REM
+@REM Distributed under the Boost Software License, Version 1.0.
+@REM See accompanying file LICENSE_1_0.txt or copy at
+@REM http://www.boost.org/LICENSE_1_0.txt
+
+SET BOOSTDEP=dist\bin\boostdep.exe
+
+FOR /f %%i IN ('git rev-parse HEAD') DO @SET REV=%%i
+
+FOR /f %%i IN ('git rev-parse --short HEAD') DO @SET SHREV=%%i
+
+FOR /f %%i IN ('git rev-parse --abbrev-ref HEAD') DO @SET BRANCH=%%i
+
+REM SET FOOTER="Generated on %DATE% %TIME% from revision %BRANCH%-%SHREV%"
+SET PREFIX="<div class='logo'><div class='upper'>boost</div><div class='lower'>Dependency Report</div><div class='description'>%BRANCH%-%SHREV%, %DATE% %TIME%</div></div><hr />"
+SET STYLESHEET=report.css
+
+SET OPTIONS=--html-stylesheet %STYLESHEET% --html-prefix %PREFIX%
+
+SET OUTDIR=..\report-%BRANCH%-%SHREV%
+
+mkdir %OUTDIR%
+
+COPY tools\boostdep\examples\%STYLESHEET% %OUTDIR%
+
+%BOOSTDEP% --list-modules > %OUTDIR%\list-modules.txt
+
+%BOOSTDEP% %OPTIONS% --html-title "Boost Module Overview" --html --module-overview > %OUTDIR%\module-overview.html
+%BOOSTDEP% %OPTIONS% --html-title "Boost Module Levels" --html --module-levels > %OUTDIR%\module-levels.html
+%BOOSTDEP% %OPTIONS% --html-title "Boost Module Weights" --html --module-weights > %OUTDIR%\module-weights.html
+
+FOR /f %%i IN (%OUTDIR%\list-modules.txt) DO %BOOSTDEP% --html-title "Boost Dependency Report for %%i" %OPTIONS% --html --primary %%i --secondary %%i --reverse %%i > %OUTDIR%\%%i.html
diff --git a/src/boost/tools/boostdep/examples/report.css b/src/boost/tools/boostdep/examples/report.css
new file mode 100644
index 000000000..b4066b574
--- /dev/null
+++ b/src/boost/tools/boostdep/examples/report.css
@@ -0,0 +1,24 @@
+/* Copyright 2017 Peter Dimov
+ Distributed under the Boost Software License, Version 1.0. */
+
+A { color: #06C; text-decoration: none; }
+A:hover { text-decoration: underline; }
+
+body { max-width: 60em; margin-left: auto; margin-right: auto; color: #4A6484; font-family: sans-serif; }
+
+.logo { font-family: sans-serif; font-style: italic; }
+.logo .upper { font-size: 48pt; font-weight: 800; }
+.logo .lower { font-size: 17pt; }
+.logo .description { font-size: small; margin-top: 2em; }
+
+.primary-list { font-size: small; }
+.secondary-list { font-size: small; }
+
+#module-overview .primary-list { margin-left: 1em; }
+
+#module-levels h3 { margin-left: 1em; }
+#module-levels .primary-list { margin-left: 2em; }
+
+#module-weights h3 { margin-left: 1em; }
+#module-weights .primary-list { margin-left: 2em; }
+#module-weights .secondary-list { margin-left: 2em; padding-left: 1em; border-left: 1px dotted; }
diff --git a/src/boost/tools/boostdep/src/boostdep.cpp b/src/boost/tools/boostdep/src/boostdep.cpp
new file mode 100644
index 000000000..22897f376
--- /dev/null
+++ b/src/boost/tools/boostdep/src/boostdep.cpp
@@ -0,0 +1,3005 @@
+
+// boostdep - a tool to generate Boost dependency reports
+//
+// Copyright 2014-2020 Peter Dimov
+//
+// Distributed under the Boost Software License, Version 1.0.
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <map>
+#include <set>
+#include <algorithm>
+#include <climits>
+#include <cstdlib>
+#include <streambuf>
+#include <sstream>
+#include <cctype>
+
+namespace fs = boost::filesystem;
+
+// header -> module
+static std::map< std::string, std::string > s_header_map;
+
+// module -> headers
+static std::map< std::string, std::set<std::string> > s_module_headers;
+
+static std::set< std::string > s_modules;
+
+static void scan_module_headers( fs::path const & path )
+{
+ try
+ {
+ std::string module = path.generic_string().substr( 5 ); // strip "libs/"
+
+ std::replace( module.begin(), module.end(), '/', '~' );
+
+ s_modules.insert( module );
+
+ fs::path dir = path / "include";
+ size_t n = dir.generic_string().size();
+
+ fs::recursive_directory_iterator it( dir ), last;
+
+ for( ; it != last; ++it )
+ {
+ if( it->status().type() == fs::directory_file )
+ {
+ continue;
+ }
+
+ std::string p2 = it->path().generic_string();
+ p2 = p2.substr( n+1 );
+
+ s_header_map[ p2 ] = module;
+ s_module_headers[ module ].insert( p2 );
+ }
+ }
+ catch( fs::filesystem_error const & x )
+ {
+ std::cout << x.what() << std::endl;
+ }
+}
+
+static void scan_submodules( fs::path const & path )
+{
+ fs::directory_iterator it( path ), last;
+
+ for( ; it != last; ++it )
+ {
+ fs::directory_entry const & e = *it;
+
+ if( e.status().type() != fs::directory_file )
+ {
+ continue;
+ }
+
+ fs::path path = e.path();
+
+ if( fs::exists( path / "include" ) )
+ {
+ scan_module_headers( path );
+ }
+
+ if( fs::exists( path / "sublibs" ) )
+ {
+ scan_submodules( path );
+ }
+ }
+}
+
+static void build_header_map()
+{
+ scan_submodules( "libs" );
+}
+
+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 )
+{
+ std::string line;
+
+ while( std::getline( is, line ) )
+ {
+ while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
+ {
+ line.erase( 0, 1 );
+ }
+
+ if( line.empty() || line[0] != '#' ) continue;
+
+ line.erase( 0, 1 );
+
+ while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
+ {
+ line.erase( 0, 1 );
+ }
+
+ if( line.substr( 0, 7 ) != "include" ) continue;
+
+ line.erase( 0, 7 );
+
+ while( !line.empty() && ( line[0] == ' ' || line[0] == '\t' ) )
+ {
+ line.erase( 0, 1 );
+ }
+
+ if( line.size() < 2 ) continue;
+
+ char ch = line[0];
+
+ if( ch != '<' && ch != '"' ) continue;
+
+ if( ch == '<' )
+ {
+ ch = '>';
+ }
+
+ line.erase( 0, 1 );
+
+ std::string::size_type k = line.find_first_of( ch );
+
+ if( k != std::string::npos )
+ {
+ line.erase( k );
+ }
+
+ std::map< std::string, std::string >::const_iterator i = s_header_map.find( line );
+
+ if( i != s_header_map.end() )
+ {
+ deps[ i->second ].insert( line );
+ from[ line ].insert( header );
+ }
+ else if( line.substr( 0, 6 ) == "boost/" )
+ {
+ deps[ "(unknown)" ].insert( line );
+ from[ line ].insert( header );
+ }
+ }
+}
+
+struct module_primary_actions
+{
+ virtual void heading( std::string const & module ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void header_start( std::string const & header ) = 0;
+ virtual void header_end( std::string const & header ) = 0;
+
+ virtual void from_header( std::string const & header ) = 0;
+};
+
+static fs::path module_include_path( std::string module )
+{
+ std::replace( module.begin(), module.end(), '~', '/' );
+ return fs::path( "libs" ) / module / "include";
+}
+
+static fs::path module_source_path( std::string module )
+{
+ std::replace( module.begin(), module.end(), '~', '/' );
+ return fs::path( "libs" ) / module / "src";
+}
+
+static fs::path module_build_path( std::string module )
+{
+ std::replace( module.begin(), module.end(), '~', '/' );
+ return fs::path( "libs" ) / module / "build";
+}
+
+static fs::path module_test_path( std::string module )
+{
+ std::replace( module.begin(), module.end(), '~', '/' );
+ return fs::path( "libs" ) / module / "test";
+}
+
+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 )
+{
+ size_t n = dir.generic_string().size();
+
+ if( fs::exists( dir ) )
+ {
+ fs::recursive_directory_iterator it( dir ), last;
+
+ for( ; it != last; ++it )
+ {
+ if( it->status().type() == fs::directory_file )
+ {
+ continue;
+ }
+
+ std::string header = it->path().generic_string();
+
+ if( remove_prefix )
+ {
+ header = header.substr( n+1 );
+ }
+
+ fs::ifstream is( it->path() );
+
+ scan_header_dependencies( header, is, deps, from );
+ }
+ }
+}
+
+static void scan_module_dependencies( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests, bool include_self )
+{
+ // module -> [ header, header... ]
+ std::map< std::string, std::set< std::string > > deps;
+
+ // header -> included from [ header, header... ]
+ std::map< std::string, std::set< std::string > > from;
+
+ scan_module_path( module_include_path( module ), true, deps, from );
+
+ if( track_sources )
+ {
+ scan_module_path( module_source_path( module ), false, deps, from );
+ }
+
+ if( track_tests )
+ {
+ scan_module_path( module_test_path( module ), false, deps, from );
+ }
+
+ actions.heading( module );
+
+ for( std::map< std::string, std::set< std::string > >::iterator i = deps.begin(); i != deps.end(); ++i )
+ {
+ if( i->first == module && !include_self ) continue;
+
+ actions.module_start( i->first );
+
+ for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ actions.header_start( *j );
+
+ std::set< std::string > const & f = from[ *j ];
+
+ for( std::set< std::string >::const_iterator k = f.begin(); k != f.end(); ++k )
+ {
+ actions.from_header( *k );
+ }
+
+ actions.header_end( *j );
+ }
+
+ actions.module_end( i->first );
+ }
+}
+
+// module depends on [ module, module... ]
+static std::map< std::string, std::set< std::string > > s_module_deps;
+
+// header is included by [header, header...]
+static std::map< std::string, std::set< std::string > > s_header_deps;
+
+// [ module, module... ] depend on module
+static std::map< std::string, std::set< std::string > > s_reverse_deps;
+
+// header includes [header, header...]
+static std::map< std::string, std::set< std::string > > s_header_includes;
+
+struct build_mdmap_actions: public module_primary_actions
+{
+ std::string module_;
+ std::string module2_;
+ std::string header_;
+
+ void heading( std::string const & module )
+ {
+ module_ = module;
+ }
+
+ void module_start( std::string const & module )
+ {
+ if( module != module_ )
+ {
+ s_module_deps[ module_ ].insert( module );
+ s_reverse_deps[ module ].insert( module_ );
+ }
+
+ module2_ = module;
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void header_start( std::string const & header )
+ {
+ header_ = header;
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ }
+
+ void from_header( std::string const & header )
+ {
+ if( module_ != module2_ )
+ {
+ s_header_deps[ header_ ].insert( header );
+ }
+
+ s_header_includes[ header ].insert( header_ );
+ }
+};
+
+static void build_module_dependency_map( bool track_sources, bool track_tests )
+{
+ for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ build_mdmap_actions actions;
+ scan_module_dependencies( *i, actions, track_sources, track_tests, true );
+ }
+}
+
+static void output_module_primary_report( std::string const & module, module_primary_actions & actions, bool track_sources, bool track_tests )
+{
+ try
+ {
+ scan_module_dependencies( module, actions, track_sources, track_tests, false );
+ }
+ catch( fs::filesystem_error const & x )
+ {
+ std::cout << x.what() << std::endl;
+ }
+}
+
+struct module_secondary_actions
+{
+ virtual void heading( std::string const & module ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void module_adds( std::string const & module ) = 0;
+};
+
+static void exclude( std::set< std::string > & x, std::set< std::string > const & y )
+{
+ for( std::set< std::string >::const_iterator i = y.begin(); i != y.end(); ++i )
+ {
+ x.erase( *i );
+ }
+}
+
+static void output_module_secondary_report( std::string const & module, std::set< std::string> deps, module_secondary_actions & actions )
+{
+ actions.heading( module );
+
+ deps.insert( module );
+
+ // build transitive closure
+
+ for( ;; )
+ {
+ std::set< std::string > deps2( deps );
+
+ for( std::set< std::string >::iterator i = deps.begin(); i != deps.end(); ++i )
+ {
+ std::set< std::string > deps3 = s_module_deps[ *i ];
+
+ exclude( deps3, deps );
+
+ if( deps3.empty() )
+ {
+ continue;
+ }
+
+ actions.module_start( *i );
+
+ for( std::set< std::string >::iterator j = deps3.begin(); j != deps3.end(); ++j )
+ {
+ actions.module_adds( *j );
+ }
+
+ actions.module_end( *i );
+
+ deps2.insert( deps3.begin(), deps3.end() );
+ }
+
+ if( deps == deps2 )
+ {
+ break;
+ }
+ else
+ {
+ deps = deps2;
+ }
+ }
+}
+
+static void output_module_secondary_report( std::string const & module, module_secondary_actions & actions )
+{
+ output_module_secondary_report( module, s_module_deps[ module ], actions );
+}
+
+struct header_inclusion_actions
+{
+ virtual void heading( std::string const & header, std::string const & module ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void header( std::string const & header ) = 0;
+};
+
+static std::string module_for_header( std::string header )
+{
+ {
+ std::map<std::string, std::string>::const_iterator i = s_header_map.find( header );
+
+ if( i != s_header_map.end() )
+ {
+ return i->second;
+ }
+ }
+
+ if( header.substr( 0, 5 ) == "libs/" )
+ {
+ header = header.substr( 5 );
+ }
+ else if( header.substr( 0, 5 ) == "test/" )
+ {
+ header = header.substr( 5 );
+ }
+ else
+ {
+ return std::string();
+ }
+
+ for( std::set<std::string>::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ std::string module = *i;
+ std::replace( module.begin(), module.end(), '~', '/' );
+
+ if( header.substr( 0, module.size() + 1 ) == module + '/' )
+ {
+ return *i;
+ }
+ }
+
+ return std::string();
+}
+
+static void output_header_inclusion_report( std::string const & header, header_inclusion_actions & actions )
+{
+ std::string module = s_header_map[ header ];
+
+ actions.heading( header, module );
+
+ std::set< std::string > from = s_header_deps[ header ];
+
+ // classify 'from' dependencies by module
+
+ // module -> [header, header...]
+ std::map< std::string, std::set< std::string > > from2;
+
+ for( std::set< std::string >::iterator i = from.begin(); i != from.end(); ++i )
+ {
+ from2[ module_for_header( *i ) ].insert( *i );
+ }
+
+ for( std::map< std::string, std::set< std::string > >::iterator i = from2.begin(); i != from2.end(); ++i )
+ {
+ actions.module_start( i->first );
+
+ for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ actions.header( *j );
+ }
+
+ actions.module_end( i->first );
+ }
+}
+
+// output_module_primary_report
+
+struct module_primary_txt_actions: public module_primary_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "Primary dependencies for " << module << ":\n\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module << ":\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void header_start( std::string const & header )
+ {
+ std::cout << " <" << header << ">\n";
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ }
+
+ void from_header( std::string const & header )
+ {
+ std::cout << " from <" << header << ">\n";
+ }
+};
+
+struct module_primary_html_actions: public module_primary_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "\n\n<h1 id=\"primary-dependencies\">Primary dependencies for <em>" << module << "</em></h1>\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h2 id=\"" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2>\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void header_start( std::string const & header )
+ {
+ std::cout << " <h3><code>&lt;" << header << "&gt;</code></h3><ul>\n";
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ std::cout << " </ul>\n";
+ }
+
+ void from_header( std::string const & header )
+ {
+ std::cout << " <li>from <code>&lt;" << header << "&gt;</code></li>\n";
+ }
+};
+
+static void output_module_primary_report( std::string const & module, bool html, bool track_sources, bool track_tests )
+{
+ if( html )
+ {
+ module_primary_html_actions actions;
+ output_module_primary_report( module, actions, track_sources, track_tests );
+ }
+ else
+ {
+ module_primary_txt_actions actions;
+ output_module_primary_report( module, actions, track_sources, track_tests );
+ }
+}
+
+// output_module_secondary_report
+
+struct module_secondary_txt_actions: public module_secondary_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "Secondary dependencies for " << module << ":\n\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module << ":\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module_adds( std::string const & module )
+ {
+ std::cout << " adds " << module << "\n";
+ }
+};
+
+struct module_secondary_html_actions: public module_secondary_actions
+{
+ std::string m2_;
+
+ void heading( std::string const & module )
+ {
+ std::cout << "\n\n<h1 id=\"secondary-dependencies\">Secondary dependencies for <em>" << module << "</em></h1>\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h2><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
+ m2_ = module;
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << " </ul>\n";
+ }
+
+ void module_adds( std::string const & module )
+ {
+ std::cout << " <li><a href=\"" << m2_ << ".html#" << module << "\">adds <em>" << module << "</em></a></li>\n";
+ }
+};
+
+static void output_module_secondary_report( std::string const & module, bool html )
+{
+ if( html )
+ {
+ module_secondary_html_actions actions;
+ output_module_secondary_report( module, actions );
+ }
+ else
+ {
+ module_secondary_txt_actions actions;
+ output_module_secondary_report( module, actions );
+ }
+}
+
+// output_header_report
+
+struct header_inclusion_txt_actions: public header_inclusion_actions
+{
+ void heading( std::string const & header, std::string const & module )
+ {
+ std::cout << "Inclusion report for <" << header << "> (in module " << module << "):\n\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " from " << module << ":\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void header( std::string const & header )
+ {
+ std::cout << " <" << header << ">\n";
+ }
+};
+
+struct header_inclusion_html_actions: public header_inclusion_actions
+{
+ void heading( std::string const & header, std::string const & module )
+ {
+ std::cout << "<h1>Inclusion report for <code>&lt;" << header << "&gt;</code> (in module <em>" << module << "</em>)</h1>\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h2>From <a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << " </ul>\n";
+ }
+
+ void header( std::string const & header )
+ {
+ std::cout << " <li><code>&lt;" << header << "&gt;</code></li>\n";
+ }
+};
+
+static void output_header_report( std::string const & header, bool html )
+{
+ if( html )
+ {
+ header_inclusion_html_actions actions;
+ output_header_inclusion_report( header, actions );
+ }
+ else
+ {
+ header_inclusion_txt_actions actions;
+ output_header_inclusion_report( header, actions );
+ }
+}
+
+// output_module_reverse_report
+
+struct module_reverse_actions
+{
+ virtual void heading( std::string const & module ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void header_start( std::string const & header ) = 0;
+ virtual void header_end( std::string const & header ) = 0;
+
+ virtual void from_header( std::string const & header ) = 0;
+};
+
+static void output_module_reverse_report( std::string const & module, module_reverse_actions & actions )
+{
+ actions.heading( module );
+
+ std::set< std::string > const from = s_reverse_deps[ module ];
+
+ for( std::set< std::string >::const_iterator i = from.begin(); i != from.end(); ++i )
+ {
+ actions.module_start( *i );
+
+ for( std::map< std::string, std::set< std::string > >::iterator j = s_header_deps.begin(); j != s_header_deps.end(); ++j )
+ {
+ if( module_for_header( j->first ) == module )
+ {
+ bool header_started = false;
+
+ for( std::set< std::string >::iterator k = j->second.begin(); k != j->second.end(); ++k )
+ {
+ if( module_for_header( *k ) == *i )
+ {
+ if( !header_started )
+ {
+ actions.header_start( j->first );
+
+ header_started = true;
+ }
+
+ actions.from_header( *k );
+ }
+ }
+
+ if( header_started )
+ {
+ actions.header_end( j->first );
+ }
+ }
+ }
+
+ actions.module_end( *i );
+ }
+}
+
+struct module_reverse_txt_actions: public module_reverse_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "Reverse dependencies for " << module << ":\n\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module << ":\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void header_start( std::string const & header )
+ {
+ std::cout << " <" << header << ">\n";
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ }
+
+ void from_header( std::string const & header )
+ {
+ std::cout << " from <" << header << ">\n";
+ }
+};
+
+struct module_reverse_html_actions: public module_reverse_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "\n\n<h1 id=\"reverse-dependencies\">Reverse dependencies for <em>" << module << "</em></h1>\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h2 id=\"reverse-" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2>\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void header_start( std::string const & header )
+ {
+ std::cout << " <h3><code>&lt;" << header << "&gt;</code></h3><ul>\n";
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ std::cout << " </ul>\n";
+ }
+
+ void from_header( std::string const & header )
+ {
+ std::cout << " <li>from <code>&lt;" << header << "&gt;</code></li>\n";
+ }
+};
+
+static void output_module_reverse_report( std::string const & module, bool html )
+{
+ if( html )
+ {
+ module_reverse_html_actions actions;
+ output_module_reverse_report( module, actions );
+ }
+ else
+ {
+ module_reverse_txt_actions actions;
+ output_module_reverse_report( module, actions );
+ }
+}
+
+// module_level_report
+
+int const unknown_level = INT_MAX / 2;
+
+struct module_level_actions
+{
+ virtual void begin() = 0;
+ virtual void end() = 0;
+
+ virtual void level_start( int level ) = 0;
+ virtual void level_end( int level ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void module2( std::string const & module, int level ) = 0;
+};
+
+static void output_module_level_report( module_level_actions & actions )
+{
+ // build module level map
+
+ std::map< std::string, int > level_map;
+
+ for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ if( s_module_deps[ *i ].empty() )
+ {
+ level_map[ *i ] = 0;
+ // std::cerr << *i << ": " << 0 << std::endl;
+ }
+ else
+ {
+ level_map[ *i ] = unknown_level;
+ }
+ }
+
+ // build transitive closure to see through cycles
+
+ std::map< std::string, std::set< std::string > > deps2 = s_module_deps;
+
+ {
+ bool done;
+
+ do
+ {
+ done = true;
+
+ for( std::map< std::string, std::set< std::string > >::iterator i = deps2.begin(); i != deps2.end(); ++i )
+ {
+ std::set< std::string > tmp = i->second;
+
+ for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ std::set< std::string > tmp2 = deps2[ *j ];
+ tmp.insert( tmp2.begin(), tmp2.end() );
+ }
+
+ if( tmp.size() != i->second.size() )
+ {
+ i->second = tmp;
+ done = false;
+ }
+ }
+ }
+ while( !done );
+ }
+
+ // compute acyclic levels
+
+ for( int k = 1, n = s_modules.size(); k < n; ++k )
+ {
+ for( std::map< std::string, std::set< std::string > >::iterator i = s_module_deps.begin(); i != s_module_deps.end(); ++i )
+ {
+ // i->first depends on i->second
+
+ if( level_map[ i->first ] >= unknown_level )
+ {
+ int level = 0;
+
+ for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ level = std::max( level, level_map[ *j ] + 1 );
+ }
+
+ if( level == k )
+ {
+ level_map[ i->first ] = level;
+ // std::cerr << i->first << ": " << level << std::endl;
+ }
+ }
+ }
+ }
+
+ // min_level_map[ M ] == L means the level is unknown, but at least L
+ std::map< std::string, int > min_level_map;
+
+ // initialize min_level_map for acyclic dependencies
+
+ for( std::map< std::string, int >::iterator i = level_map.begin(); i != level_map.end(); ++i )
+ {
+ if( i->second < unknown_level )
+ {
+ min_level_map[ i->first ] = i->second;
+ }
+ }
+
+ // compute levels for cyclic modules
+
+ for( int k = 1, n = s_modules.size(); k < n; ++k )
+ {
+ for( std::map< std::string, std::set< std::string > >::iterator i = s_module_deps.begin(); i != s_module_deps.end(); ++i )
+ {
+ if( level_map[ i->first ] >= unknown_level )
+ {
+ int level = 0;
+
+ for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ int jl = level_map[ *j ];
+
+ if( jl < unknown_level )
+ {
+ level = std::max( level, jl + 1 );
+ }
+ else
+ {
+ int ml = min_level_map[ *j ];
+
+ if( deps2[ *j ].count( i->first ) == 0 )
+ {
+ // *j does not depend on i->first, so
+ // the level of i->first is at least
+ // 1 + the minimum level of *j
+
+ ++ml;
+ }
+
+ level = std::max( level, ml );
+ }
+ }
+
+ min_level_map[ i->first ] = level;
+ }
+ }
+ }
+
+ // reverse level map
+
+ std::map< int, std::set< std::string > > reverse_level_map;
+
+ for( std::map< std::string, int >::iterator i = level_map.begin(); i != level_map.end(); ++i )
+ {
+ int level = i->second;
+
+ if( level >= unknown_level )
+ {
+ int min_level = min_level_map[ i->first ];
+
+ if( min_level != 0 )
+ {
+ level = min_level;
+ }
+ }
+
+ reverse_level_map[ level ].insert( i->first );
+ }
+
+ // output report
+
+ actions.begin();
+
+ for( std::map< int, std::set< std::string > >::iterator i = reverse_level_map.begin(); i != reverse_level_map.end(); ++i )
+ {
+ actions.level_start( i->first );
+
+ for( std::set< std::string >::iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ actions.module_start( *j );
+
+ std::set< std::string > mdeps = s_module_deps[ *j ];
+
+ for( std::set< std::string >::iterator k = mdeps.begin(); k != mdeps.end(); ++k )
+ {
+ int level = level_map[ *k ];
+
+ if( level >= unknown_level )
+ {
+ int min_level = min_level_map[ *k ];
+
+ if( min_level != 0 )
+ {
+ level = min_level;
+ }
+ }
+
+ actions.module2( *k, level );
+ }
+
+ actions.module_end( *j );
+ }
+
+ actions.level_end( i->first );
+ }
+
+ actions.end();
+}
+
+struct module_level_txt_actions: public module_level_actions
+{
+ int level_;
+
+ void begin()
+ {
+ std::cout << "Module Levels:\n\n";
+ }
+
+ void end()
+ {
+ }
+
+ void level_start( int level )
+ {
+ if( level >= unknown_level )
+ {
+ std::cout << "Level (undetermined):\n";
+ }
+ else
+ {
+ std::cout << "Level " << level << ":\n";
+ }
+
+ level_ = level;
+ }
+
+ void level_end( int /*level*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " " << module;
+
+ if( level_ > 0 )
+ {
+ std::cout << " ->";
+ }
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module2( std::string const & module, int level )
+ {
+ std::cout << " " << module << "(";
+
+ if( level >= unknown_level )
+ {
+ std::cout << "-";
+ }
+ else
+ {
+ std::cout << level;
+ }
+
+ std::cout << ")";
+ }
+};
+
+struct module_level_html_actions: public module_level_actions
+{
+ int level_;
+
+ void begin()
+ {
+ std::cout << "<div id='module-levels'><h1>Module Levels</h1>\n";
+ }
+
+ void end()
+ {
+ std::cout << "</div>\n";
+ }
+
+ void level_start( int level )
+ {
+ if( level >= unknown_level )
+ {
+ std::cout << " <h2>Level <em>undetermined</em></h2>\n";
+ }
+ else
+ {
+ std::cout << " <h2 id='level:" << level << "'>Level " << level << "</h2>\n";
+ }
+
+ level_ = level;
+ }
+
+ void level_end( int /*level*/ )
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3><p class='primary-list'>";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "</p>\n";
+ }
+
+ void module2( std::string const & module, int level )
+ {
+ std::cout << " ";
+
+ bool important = level < unknown_level && level > 1 && level >= level_ - 1;
+
+ if( important )
+ {
+ std::cout << "<strong>";
+ }
+
+ std::cout << module;
+
+ if( level < unknown_level )
+ {
+ std::cout << "<sup>" << level << "</sup>";
+ }
+
+ if( important )
+ {
+ std::cout << "</strong>";
+ }
+ }
+};
+
+static void output_module_level_report( bool html )
+{
+ if( html )
+ {
+ module_level_html_actions actions;
+ output_module_level_report( actions );
+ }
+ else
+ {
+ module_level_txt_actions actions;
+ output_module_level_report( actions );
+ }
+}
+
+// module_overview_report
+
+struct module_overview_actions
+{
+ virtual void begin() = 0;
+ virtual void end() = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void module2( std::string const & module ) = 0;
+};
+
+static void output_module_overview_report( module_overview_actions & actions )
+{
+ actions.begin();
+
+ for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ actions.module_start( *i );
+
+ std::set< std::string > const mdeps = s_module_deps[ *i ];
+
+ for( std::set< std::string >::const_iterator j = mdeps.begin(); j != mdeps.end(); ++j )
+ {
+ actions.module2( *j );
+ }
+
+ actions.module_end( *i );
+ }
+
+ actions.end();
+}
+
+struct module_overview_txt_actions: public module_overview_actions
+{
+ bool deps_;
+
+ void begin()
+ {
+ std::cout << "Module Overview:\n\n";
+ }
+
+ void end()
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module;
+ deps_ = false;
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module2( std::string const & module )
+ {
+ if( !deps_ )
+ {
+ std::cout << " ->";
+ deps_ = true;
+ }
+
+ std::cout << " " << module;
+ }
+};
+
+struct module_overview_html_actions: public module_overview_actions
+{
+ void begin()
+ {
+ std::cout << "<div id='module-overview'><h1>Module Overview</h1>\n";
+ }
+
+ void end()
+ {
+ std::cout << "</div>\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h2 id='" << module << "'><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><p class='primary-list'>";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "</p>\n";
+ }
+
+ void module2( std::string const & module )
+ {
+ std::cout << " " << module;
+ }
+};
+
+static void output_module_overview_report( bool html )
+{
+ if( html )
+ {
+ module_overview_html_actions actions;
+ output_module_overview_report( actions );
+ }
+ else
+ {
+ module_overview_txt_actions actions;
+ output_module_overview_report( actions );
+ }
+}
+
+// list_dependencies
+
+struct list_dependencies_actions: public module_overview_actions
+{
+ void begin()
+ {
+ }
+
+ void end()
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module << " ->";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module2( std::string const & module )
+ {
+ if( module != "(unknown)" )
+ {
+ std::cout << " " << module;
+ }
+ }
+};
+
+static void list_dependencies()
+{
+ list_dependencies_actions actions;
+ output_module_overview_report( actions );
+}
+
+//
+
+static void output_html_header( std::string const & title, std::string const & stylesheet, std::string const & prefix )
+{
+ std::cout << "<html>\n";
+ std::cout << "<head>\n";
+ std::cout << "<title>" << title << "</title>\n";
+
+ if( !stylesheet.empty() )
+ {
+ std::cout << "<link rel=\"stylesheet\" type=\"text/css\" href=\"" << stylesheet << "\" />\n";
+ }
+
+ std::cout << "</head>\n";
+ std::cout << "<body>\n";
+
+ if( !prefix.empty() )
+ {
+ std::cout << prefix << std::endl;
+ }
+}
+
+static void output_html_footer( std::string const & footer )
+{
+ std::cout << "<hr />\n";
+ std::cout << "<p class=\"footer\">" << footer << "</p>\n";
+ std::cout << "</body>\n";
+ std::cout << "</html>\n";
+}
+
+static void enable_secondary( bool & secondary, bool track_sources, bool track_tests )
+{
+ if( !secondary )
+ {
+ try
+ {
+ build_module_dependency_map( track_sources, track_tests );
+ }
+ catch( fs::filesystem_error const & x )
+ {
+ std::cout << x.what() << std::endl;
+ }
+
+ secondary = true;
+ }
+}
+
+static void list_modules()
+{
+ for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ std::cout << *i << "\n";
+ }
+}
+
+static void list_buildable()
+{
+ for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ if( fs::exists( module_build_path( *i ) ) && fs::exists( module_source_path( *i ) ) )
+ {
+ std::cout << *i << "\n";
+ }
+ }
+}
+
+// module_weight_report
+
+struct module_weight_actions
+{
+ virtual void begin() = 0;
+ virtual void end() = 0;
+
+ virtual void weight_start( int weight ) = 0;
+ virtual void weight_end( int weight ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void module_primary_start() = 0;
+ virtual void module_primary( std::string const & module, int weight ) = 0;
+ virtual void module_primary_end() = 0;
+
+ virtual void module_secondary_start() = 0;
+ virtual void module_secondary( std::string const & module, int weight ) = 0;
+ virtual void module_secondary_end() = 0;
+};
+
+static void output_module_weight_report( module_weight_actions & actions )
+{
+ // gather secondary dependencies
+
+ struct build_secondary_deps: public module_secondary_actions
+ {
+ std::map< std::string, std::set< std::string > > * pm_;
+
+ build_secondary_deps( std::map< std::string, std::set< std::string > > * pm ): pm_( pm )
+ {
+ }
+
+ std::string module_;
+
+ void heading( std::string const & module )
+ {
+ module_ = module;
+ }
+
+ void module_start( std::string const & /*module*/ )
+ {
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void module_adds( std::string const & module )
+ {
+ (*pm_)[ module_ ].insert( module );
+ }
+ };
+
+ std::map< std::string, std::set< std::string > > secondary_deps;
+
+ build_secondary_deps bsd( &secondary_deps );
+
+ for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ output_module_secondary_report( *i, bsd );
+ }
+
+ // build weight map
+
+ std::map< int, std::set< std::string > > modules_by_weight;
+
+ for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ int w = s_module_deps[ *i ].size() + secondary_deps[ *i ].size();
+ modules_by_weight[ w ].insert( *i );
+ }
+
+ // output report
+
+ actions.begin();
+
+ for( std::map< int, std::set< std::string > >::const_iterator i = modules_by_weight.begin(); i != modules_by_weight.end(); ++i )
+ {
+ actions.weight_start( i->first );
+
+ for( std::set< std::string >::const_iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ actions.module_start( *j );
+
+ if( !s_module_deps[ *j ].empty() )
+ {
+ actions.module_primary_start();
+
+ for( std::set< std::string >::const_iterator k = s_module_deps[ *j ].begin(); k != s_module_deps[ *j ].end(); ++k )
+ {
+ int w = s_module_deps[ *k ].size() + secondary_deps[ *k ].size();
+ actions.module_primary( *k, w );
+ }
+
+ actions.module_primary_end();
+ }
+
+ if( !secondary_deps[ *j ].empty() )
+ {
+ actions.module_secondary_start();
+
+ for( std::set< std::string >::const_iterator k = secondary_deps[ *j ].begin(); k != secondary_deps[ *j ].end(); ++k )
+ {
+ int w = s_module_deps[ *k ].size() + secondary_deps[ *k ].size();
+ actions.module_secondary( *k, w );
+ }
+
+ actions.module_secondary_end();
+ }
+
+ actions.module_end( *j );
+ }
+
+ actions.weight_end( i->first );
+ }
+
+ actions.end();
+}
+
+struct module_weight_txt_actions: public module_weight_actions
+{
+ void begin()
+ {
+ std::cout << "Module Weights:\n\n";
+ }
+
+ void end()
+ {
+ }
+
+ void weight_start( int weight )
+ {
+ std::cout << "Weight " << weight << ":\n";
+ }
+
+ void weight_end( int /*weight*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " " << module;
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module_primary_start()
+ {
+ std::cout << " ->";
+ }
+
+ void module_primary( std::string const & module, int weight )
+ {
+ std::cout << " " << module << "(" << weight << ")";
+ }
+
+ void module_primary_end()
+ {
+ }
+
+ void module_secondary_start()
+ {
+ std::cout << " ->";
+ }
+
+ void module_secondary( std::string const & module, int /*weight*/ )
+ {
+ std::cout << " " << module;
+ }
+
+ void module_secondary_end()
+ {
+ }
+};
+
+struct module_weight_html_actions: public module_weight_actions
+{
+ int weight_;
+
+ void begin()
+ {
+ std::cout << "<div id='module-weights'>\n<h1>Module Weights</h1>\n";
+ }
+
+ void end()
+ {
+ std::cout << "</div>\n";
+ }
+
+ void weight_start( int weight )
+ {
+ std::cout << " <h2 id='weight:" << weight << "'>Weight " << weight << "</h2>\n";
+ weight_ = weight;
+ }
+
+ void weight_end( int /*weight*/ )
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h3 id='" << module << "'><a href=\"" << module << ".html\">" << module << "</a></h3>";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void module_primary_start()
+ {
+ std::cout << "<p class='primary-list'>";
+ }
+
+ void module_primary( std::string const & module, int weight )
+ {
+ std::cout << " ";
+
+ bool heavy = weight >= 0.8 * weight_;
+
+ if( heavy )
+ {
+ std::cout << "<strong>";
+ }
+
+ std::cout << module << "<sup>" << weight << "</sup>";
+
+ if( heavy )
+ {
+ std::cout << "</strong>";
+ }
+ }
+
+ void module_primary_end()
+ {
+ std::cout << "</p>";
+ }
+
+ void module_secondary_start()
+ {
+ std::cout << "<p class='secondary-list'>";
+ }
+
+ void module_secondary( std::string const & module, int /*weight*/ )
+ {
+ std::cout << " " << module;
+ }
+
+ void module_secondary_end()
+ {
+ std::cout << "</p>";
+ }
+};
+
+static void output_module_weight_report( bool html )
+{
+ if( html )
+ {
+ module_weight_html_actions actions;
+ output_module_weight_report( actions );
+ }
+ else
+ {
+ module_weight_txt_actions actions;
+ output_module_weight_report( actions );
+ }
+}
+
+// output_module_subset_report
+
+struct module_subset_actions
+{
+ virtual void heading( std::string const & module ) = 0;
+
+ virtual void module_start( std::string const & module ) = 0;
+ virtual void module_end( std::string const & module ) = 0;
+
+ virtual void from_path( std::vector<std::string> const & path ) = 0;
+};
+
+static void add_module_headers( fs::path const & dir, std::set<std::string> & headers )
+{
+ if( fs::exists( dir ) )
+ {
+ fs::recursive_directory_iterator it( dir ), last;
+
+ for( ; it != last; ++it )
+ {
+ if( it->status().type() == fs::directory_file )
+ {
+ continue;
+ }
+
+ headers.insert( it->path().generic_string() );
+ }
+ }
+}
+
+static void output_module_subset_report_( std::string const & module, std::set<std::string> const & headers, module_subset_actions & actions )
+{
+ // build header closure
+
+ // header -> (header)*
+ std::map< std::string, std::set<std::string> > inc2;
+
+ // (header, header) -> path
+ std::map< std::pair<std::string, std::string>, std::vector<std::string> > paths;
+
+ for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
+ {
+ std::set<std::string> & s = inc2[ *i ];
+
+ s = s_header_includes[ *i ];
+
+ for( std::set<std::string>::const_iterator j = s.begin(); j != s.end(); ++j )
+ {
+ std::vector<std::string> & v = paths[ std::make_pair( *i, *j ) ];
+
+ v.resize( 0 );
+ v.push_back( *i );
+ v.push_back( *j );
+ }
+ }
+
+ for( ;; )
+ {
+ bool r = false;
+
+ for( std::map< std::string, std::set<std::string> >::iterator i = inc2.begin(); i != inc2.end(); ++i )
+ {
+ std::set<std::string> & s2 = i->second;
+
+ for( std::set<std::string>::const_iterator j = s2.begin(); j != s2.end(); ++j )
+ {
+ std::set<std::string> const & s = s_header_includes[ *j ];
+
+ for( std::set<std::string>::const_iterator k = s.begin(); k != s.end(); ++k )
+ {
+ if( s2.count( *k ) == 0 )
+ {
+ s2.insert( *k );
+
+ std::vector<std::string> const & v1 = paths[ std::make_pair( i->first, *j ) ];
+ std::vector<std::string> & v2 = paths[ std::make_pair( i->first, *k ) ];
+
+ v2 = v1;
+ v2.push_back( *k );
+
+ r = true;
+ }
+ }
+ }
+ }
+
+ if( !r ) break;
+ }
+
+ // module -> header -> path [header -> header -> header]
+ std::map< std::string, std::map< std::string, std::vector<std::string> > > subset;
+
+ for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
+ {
+ std::set<std::string> const & s = inc2[ *i ];
+
+ for( std::set<std::string>::const_iterator j = s.begin(); j != s.end(); ++j )
+ {
+ std::string const & m = s_header_map[ *j ];
+
+ if( m.empty() ) continue;
+
+ std::vector<std::string> const & path = paths[ std::make_pair( *i, *j ) ];
+
+ if( subset.count( m ) == 0 || subset[ m ].count( *i ) == 0 || subset[ m ][ *i ].size() > path.size() )
+ {
+ subset[ m ][ *i ] = path;
+ }
+ }
+ }
+
+ actions.heading( module );
+
+ for( std::map< std::string, std::map< std::string, std::vector<std::string> > >::const_iterator i = subset.begin(); i != subset.end(); ++i )
+ {
+ if( i->first == module ) continue;
+
+ actions.module_start( i->first );
+
+ int k = 0;
+
+ for( std::map< std::string, std::vector<std::string> >::const_iterator j = i->second.begin(); j != i->second.end() && k < 4; ++j, ++k )
+ {
+ actions.from_path( j->second );
+ }
+
+ actions.module_end( i->first );
+ }
+}
+
+static void output_module_subset_report( std::string const & module, bool track_sources, bool track_tests, module_subset_actions & actions )
+{
+ std::set<std::string> headers = s_module_headers[ module ];
+
+ if( track_sources )
+ {
+ add_module_headers( module_source_path( module ), headers );
+ }
+
+ if( track_tests )
+ {
+ add_module_headers( module_test_path( module ), headers );
+ }
+
+ output_module_subset_report_( module, headers, actions );
+}
+
+struct module_subset_txt_actions: public module_subset_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "Subset dependencies for " << module << ":\n\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module << ":\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "\n";
+ }
+
+ void from_path( std::vector<std::string> const & path )
+ {
+ for( std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i )
+ {
+ if( i == path.begin() )
+ {
+ std::cout << " ";
+ }
+ else
+ {
+ std::cout << " -> ";
+ }
+
+ std::cout << *i;
+ }
+
+ std::cout << "\n";
+ }
+};
+
+struct module_subset_html_actions: public module_subset_actions
+{
+ void heading( std::string const & module )
+ {
+ std::cout << "\n\n<h1 id=\"subset-dependencies\">Subset dependencies for <em>" << module << "</em></h1>\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << " <h2 id=\"subset-" << module << "\"><a href=\"" << module << ".html\"><em>" << module << "</em></a></h2><ul>\n";
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ std::cout << "</ul>\n";
+ }
+
+ void from_path( std::vector<std::string> const & path )
+ {
+ std::cout << " <li>";
+
+ for( std::vector<std::string>::const_iterator i = path.begin(); i != path.end(); ++i )
+ {
+ if( i != path.begin() )
+ {
+ std::cout << " &#8674; ";
+ }
+
+ std::cout << "<code>" << *i << "</code>";
+ }
+
+ std::cout << "</li>\n";
+ }
+};
+
+static void output_module_subset_report( std::string const & module, bool track_sources, bool track_tests, bool html )
+{
+ if( html )
+ {
+ module_subset_html_actions actions;
+ output_module_subset_report( module, track_sources, track_tests, actions );
+ }
+ else
+ {
+ module_subset_txt_actions actions;
+ output_module_subset_report( module, track_sources, track_tests, actions );
+ }
+}
+
+// --list-exceptions
+
+static void list_exceptions()
+{
+ std::string lm;
+
+ for( std::map< std::string, std::set<std::string> >::const_iterator i = s_module_headers.begin(); i != s_module_headers.end(); ++i )
+ {
+ std::string module = i->first;
+
+ std::replace( module.begin(), module.end(), '~', '/' );
+
+ std::string const prefix = "boost/" + module;
+ size_t const n = prefix.size();
+
+ for( std::set< std::string >::const_iterator j = i->second.begin(); j != i->second.end(); ++j )
+ {
+ std::string const & header = *j;
+
+ if( header.substr( 0, n+1 ) != prefix + '/' && header != prefix + ".hpp" )
+ {
+ if( lm != module )
+ {
+ std::cout << module << ":\n";
+ lm = module;
+ }
+
+ std::cout << " " << header << '\n';
+ }
+ }
+ }
+}
+
+// --test
+
+struct module_test_primary_actions: public module_primary_actions
+{
+ std::set< std::string > & m_;
+
+ module_test_primary_actions( std::set< std::string > & m ): m_( m )
+ {
+ }
+
+ void heading( std::string const & module )
+ {
+ std::cout << "Test dependencies for " << module << ":\n\n";
+ }
+
+ void module_start( std::string const & module )
+ {
+ std::cout << module << "\n";
+ m_.insert( module );
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void header_start( std::string const & /*header*/ )
+ {
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ }
+
+ void from_header( std::string const & /*header*/ )
+ {
+ }
+};
+
+struct module_test_secondary_actions: public module_secondary_actions
+{
+ std::set< std::string > & m_;
+ std::string m2_;
+
+ module_test_secondary_actions( std::set< std::string > & m ): m_( m )
+ {
+ }
+
+ void heading( std::string const & /*module*/ )
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ m2_ = module;
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void module_adds( std::string const & module )
+ {
+ if( m_.count( module ) == 0 )
+ {
+ std::cout << module << " (from " << m2_ << ")\n";
+ m_.insert( module );
+ }
+ }
+};
+
+static void output_module_test_report( std::string const & module )
+{
+ std::set< std::string > m;
+
+ module_test_primary_actions a1( m );
+ output_module_primary_report( module, a1, true, true );
+
+ std::cout << "\n";
+
+ bool secondary = false;
+ enable_secondary( secondary, true, false );
+
+ std::set< std::string > m2( m );
+ m2.insert( module );
+
+ module_test_secondary_actions a2( m2 );
+
+ output_module_secondary_report( module, m, a2 );
+}
+
+// --cmake
+
+struct collect_primary_dependencies: public module_primary_actions
+{
+ std::set< std::string > set_;
+
+ void heading( std::string const & )
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ if( module == "(unknown)" ) return;
+
+ set_.insert( module );
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void header_start( std::string const & /*header*/ )
+ {
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ }
+
+ void from_header( std::string const & /*header*/ )
+ {
+ }
+};
+
+static std::string module_cmake_name( std::string module )
+{
+ std::replace( module.begin(), module.end(), '~', '_' );
+ return module;
+}
+
+static void output_module_cmake_report( std::string module )
+{
+ std::cout <<
+
+ "# Generated by `boostdep --cmake " << module << "`\n"
+ "# Copyright 2020 Peter Dimov\n"
+ "# Distributed under the Boost Software License, Version 1.0.\n"
+ "# https://www.boost.org/LICENSE_1_0.txt\n"
+ "\n"
+ "cmake_minimum_required(VERSION 3.5...3.16)\n"
+ "\n"
+ ;
+
+ std::replace( module.begin(), module.end(), '/', '~' );
+
+ std::vector<std::string> sources;
+ bool has_c_sources = false;
+
+ fs::path srcpath = module_source_path( module );
+
+ if( fs::exists( srcpath ) )
+ {
+ fs::directory_iterator it( srcpath ), last;
+
+ for( ; it != last; ++it )
+ {
+ if( it->status().type() != fs::regular_file ) continue;
+
+ fs::path p = it->path();
+ std::string ext = p.extension().string();
+
+ if( ext != ".cpp" && ext != ".c" ) continue;
+
+ std::string name = p.filename().string();
+
+ sources.push_back( name );
+
+ if( ext == ".c" ) has_c_sources = true;
+ }
+ }
+
+ std::string lm( module );
+
+ std::replace( lm.begin(), lm.end(), '~', '_' );
+
+ std::cout <<
+
+ "project(boost_" << lm << " VERSION \"${BOOST_SUPERPROJECT_VERSION}\" LANGUAGES" << ( has_c_sources? " C": "" ) << " CXX)\n"
+ "\n"
+ ;
+
+ collect_primary_dependencies a1;
+ output_module_primary_report( module, a1, false, false );
+
+ if( !fs::exists( srcpath ) )
+ {
+ // header-only library
+
+ std::cout <<
+
+ "add_library(boost_" << lm << " INTERFACE)\n"
+ "add_library(Boost::" << lm << " ALIAS boost_" << lm << ")\n"
+ "\n"
+ "target_include_directories(boost_" << lm << " INTERFACE include)\n"
+ "\n"
+ ;
+
+ if( !a1.set_.empty() )
+ {
+ std::cout <<
+
+ "target_link_libraries(boost_" << lm << "\n"
+ " INTERFACE\n"
+ ;
+
+ for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ {
+ std::cout << " Boost::" << module_cmake_name( *i ) << "\n";
+ }
+
+ std::cout <<
+
+ ")\n"
+ "\n"
+ ;
+ }
+ }
+ else
+ {
+ // compiled library
+
+ std::cout <<
+
+ "add_library(boost_" << lm << "\n";
+
+ for( std::vector<std::string>::iterator i = sources.begin(); i != sources.end(); ++i )
+ {
+ std::cout << " src/" << *i << "\n";
+ }
+
+ std::cout <<
+
+ ")\n"
+ "\n"
+ "add_library(Boost::" << lm << " ALIAS boost_" << lm << ")\n"
+ "\n"
+ "target_include_directories(boost_" << lm << " PUBLIC include)\n"
+ "\n"
+ ;
+
+ collect_primary_dependencies a2;
+ output_module_primary_report( module, a2, true, false );
+
+ if( !a1.set_.empty() || !a2.set_.empty() )
+ {
+ std::cout <<
+
+ "target_link_libraries(boost_" << lm << "\n"
+ ;
+
+ if( !a1.set_.empty() )
+ {
+ std::cout <<
+
+ " PUBLIC\n"
+ ;
+
+ for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ {
+ a2.set_.erase( *i );
+ std::cout << " Boost::" << module_cmake_name( *i ) << "\n";
+ }
+ }
+
+ if( !a2.set_.empty() )
+ {
+ std::cout <<
+
+ " PRIVATE\n"
+ ;
+
+ for( std::set< std::string >::const_iterator i = a2.set_.begin(); i != a2.set_.end(); ++i )
+ {
+ std::cout << " Boost::" << module_cmake_name( *i ) << "\n";
+ }
+ }
+
+ std::cout <<
+
+ ")\n"
+ "\n"
+ ;
+ }
+
+ std::string um( lm );
+
+ for( std::string::iterator i = um.begin(); i != um.end(); ++i )
+ {
+ *i = std::toupper( static_cast<unsigned char>( *i ) );
+ }
+
+ std::cout <<
+
+ "target_compile_definitions(boost_" << lm << "\n"
+ " PUBLIC BOOST_" << um << "_NO_LIB\n"
+ " PRIVATE BOOST_" << um << "_SOURCE\n"
+ ")\n"
+ "\n"
+ "if(BUILD_SHARED_LIBS)\n"
+ " target_compile_definitions(boost_" << lm << " PUBLIC BOOST_" << um << "_DYN_LINK)\n"
+ "else()\n"
+ " target_compile_definitions(boost_" << lm << " PUBLIC BOOST_" << um << "_STATIC_LINK)\n"
+ "endif()\n"
+ "\n"
+ ;
+ }
+
+ std::cout <<
+
+ "if(BUILD_TESTING AND EXISTS \"${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt\")\n"
+ "\n"
+ " add_subdirectory(test)\n"
+ "\n"
+ "endif()\n"
+ "\n"
+ ;
+}
+
+// --list-missing-headers
+
+struct missing_header_actions: public module_primary_actions
+{
+ std::string module_, module2_;
+
+ void heading( std::string const & module )
+ {
+ module_ = module;
+ }
+
+ void module_start( std::string const & module )
+ {
+ module2_ = module;
+ }
+
+ void module_end( std::string const & /*module*/ )
+ {
+ }
+
+ void header_start( std::string const & header )
+ {
+ if( module2_ == "(unknown)" )
+ {
+ if( !module_.empty() )
+ {
+ std::cout << module_ << ":\n";
+ module_.clear();
+ }
+
+ std::cout << " <" << header << ">\n";
+ }
+ }
+
+ void header_end( std::string const & /*header*/ )
+ {
+ }
+
+ void from_header( std::string const & header )
+ {
+ if( module2_ == "(unknown)" )
+ {
+ std::cout << " from <" << header << ">\n";
+ }
+ }
+};
+
+static void list_missing_headers( std::string const & module )
+{
+ missing_header_actions a;
+ output_module_primary_report( module, a, false, false );
+}
+
+static void list_missing_headers()
+{
+ for( std::set< std::string >::const_iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ list_missing_headers( *i );
+ }
+}
+
+// --pkgconfig
+
+struct primary_pkgconfig_actions: public module_primary_actions
+{
+ std::string version_;
+ std::string list_;
+
+ void heading( std::string const & )
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ if( module == "(unknown)" ) return;
+
+ std::string m2( module );
+ std::replace( m2.begin(), m2.end(), '~', '_' );
+
+ if( !list_.empty() )
+ {
+ list_ += ", ";
+ }
+
+ list_ += "boost_" + m2 + " = " + version_;
+ }
+
+ void module_end( std::string const & )
+ {
+ }
+
+ void header_start( std::string const & )
+ {
+ }
+
+ void header_end( std::string const & )
+ {
+ }
+
+ void from_header( std::string const & )
+ {
+ }
+};
+
+static void output_requires( std::string const & section, std::string const & version, std::set< std::string > const & s )
+{
+ bool first = true;
+
+ for( std::set< std::string >::const_iterator i = s.begin(); i != s.end(); ++i )
+ {
+ if( first )
+ {
+ std::cout << section << ": ";
+ first = false;
+ }
+ else
+ {
+ std::cout << ", ";
+ }
+
+ std::string m2( *i );
+ std::replace( m2.begin(), m2.end(), '~', '_' );
+
+ std::cout << "boost_" << m2 << " = " << version;
+ }
+}
+
+static void output_pkgconfig( std::string const & module, std::string const & version, int argc, char const* argv[] )
+{
+ for( int i = 0; i < argc; ++i )
+ {
+ std::cout << argv[ i ] << '\n';
+ }
+
+ std::cout << '\n';
+
+ std::string m2( module );
+ std::replace( m2.begin(), m2.end(), '/', '_' );
+
+ std::string m3( module );
+ std::replace( m3.begin(), m3.end(), '/', '~' );
+
+ std::cout << "Name: boost_" << module << '\n';
+ std::cout << "Description: Boost C++ library '" << module << "'\n";
+ std::cout << "Version: " << version << '\n';
+ std::cout << "URL: http://www.boost.org/libs/" << module << '\n';
+ std::cout << "Cflags: -I${includedir}\n";
+
+ if( fs::exists( module_build_path( module ) ) && fs::exists( module_source_path( module ) ) )
+ {
+ std::cout << "Libs: -L${libdir} -lboost_" << m2 << "\n";
+ }
+
+ collect_primary_dependencies a1;
+ output_module_primary_report( m3, a1, false, false );
+
+ if( !a1.set_.empty() )
+ {
+ output_requires( "Requires", version, a1.set_ );
+ std::cout << std::endl;
+ }
+
+ collect_primary_dependencies a2;
+ output_module_primary_report( m3, a2, true, false );
+
+ for( std::set< std::string >::const_iterator i = a1.set_.begin(); i != a1.set_.end(); ++i )
+ {
+ a2.set_.erase( *i );
+ }
+
+ if( !a2.set_.empty() )
+ {
+ output_requires( "Requires.private", version, a2.set_ );
+ std::cout << std::endl;
+ }
+}
+
+// --subset-for
+
+static void output_directory_subset_report( std::string const & module, std::set<std::string> const & headers, bool html )
+{
+ for( std::set<std::string>::const_iterator i = headers.begin(); i != headers.end(); ++i )
+ {
+ std::map< std::string, std::set< std::string > > deps;
+ std::map< std::string, std::set< std::string > > from;
+
+ std::ifstream is( i->c_str() );
+ scan_header_dependencies( *i, is, deps, from );
+
+ for( std::map< std::string, std::set< std::string > >::const_iterator j = from.begin(); j != from.end(); ++j )
+ {
+ for( std::set<std::string>::const_iterator k = j->second.begin(); k != j->second.end(); ++k )
+ {
+ s_header_includes[ *k ].insert( j->first );
+ }
+ }
+ }
+
+ if( html )
+ {
+ module_subset_html_actions actions;
+ output_module_subset_report_( module, headers, actions );
+ }
+ else
+ {
+ module_subset_txt_actions actions;
+ output_module_subset_report_( module, headers, actions );
+ }
+}
+
+// list_buildable_dependencies
+
+struct list_buildable_dependencies_actions: public module_overview_actions
+{
+ std::set< std::string > buildable_;
+
+ std::set< std::string > deps_;
+ bool headers_;
+
+ list_buildable_dependencies_actions(): headers_()
+ {
+ }
+
+ void begin()
+ {
+ std::cout << "# Generated by `boostdep --list-buildable-dependencies`\n\n";
+ }
+
+ void end()
+ {
+ }
+
+ void module_start( std::string const & module )
+ {
+ deps_.clear();
+ headers_ = false;
+
+ if( buildable_.count( module ) )
+ {
+ std::cout << module << " =";
+ }
+ }
+
+ void module_end( std::string const & module )
+ {
+ if( buildable_.count( module ) )
+ {
+ if( headers_ )
+ {
+ std::cout << " headers";
+ }
+
+ for( std::set< std::string >::iterator i = deps_.begin(); i != deps_.end(); ++i )
+ {
+ std::cout << " " << *i;
+ }
+
+ std::cout << " ;\n";
+ }
+ }
+
+ void module2( std::string const & module )
+ {
+ if( module == "(unknown)" ) return;
+
+ if( buildable_.count( module ) == 0 )
+ {
+ headers_ = true;
+ }
+ else
+ {
+ deps_.insert( module );
+ }
+ }
+};
+
+static void list_buildable_dependencies()
+{
+ list_buildable_dependencies_actions actions;
+
+ for( std::set< std::string >::iterator i = s_modules.begin(); i != s_modules.end(); ++i )
+ {
+ if( fs::exists( module_build_path( *i ) ) && fs::exists( module_source_path( *i ) ) )
+ {
+ actions.buildable_.insert( *i );
+ }
+ }
+
+ output_module_overview_report( actions );
+}
+
+//
+
+static bool find_boost_root()
+{
+ for( int i = 0; i < 32; ++i )
+ {
+ if( fs::exists( "Jamroot" ) )
+ {
+ return true;
+ }
+
+ fs::path p = fs::current_path();
+
+ if( p == p.root_path() )
+ {
+ return false;
+ }
+
+ fs::current_path( p.parent_path() );
+ }
+
+ return false;
+}
+
+static bool is_boost_root( fs::path const & p )
+{
+ return fs::exists( p / "Jamroot" );
+}
+
+// teebuf
+
+class teebuf: public std::streambuf
+{
+private:
+
+ std::streambuf * sb1_;
+ std::streambuf * sb2_;
+
+public:
+
+ teebuf( std::streambuf * sb1, std::streambuf * sb2 ): sb1_( sb1 ), sb2_( sb2 )
+ {
+ }
+
+private:
+
+ virtual int overflow( int c )
+ {
+ int r1 = sb1_->sputc( c );
+ int r2 = sb2_->sputc( c );
+
+ return r1 == EOF || r2 == EOF? EOF : c;
+ }
+
+ virtual int sync()
+ {
+ int r1 = sb1_->pubsync();
+ int r2 = sb2_->pubsync();
+
+ return r1 == 0 && r2 == 0? 0 : -1;
+ }
+};
+
+// save_cout_rdbuf
+
+class save_cout_rdbuf
+{
+private:
+
+ std::streambuf * sb_;
+
+public:
+
+ save_cout_rdbuf(): sb_( std::cout.rdbuf() )
+ {
+ }
+
+ ~save_cout_rdbuf()
+ {
+ std::cout.rdbuf( sb_ );
+ }
+};
+
+// main
+
+int main( int argc, char const* argv[] )
+{
+ if( argc < 2 )
+ {
+ std::cout <<
+
+ "Usage:\n"
+ "\n"
+ " boostdep --list-modules\n"
+ " boostdep --list-buildable\n"
+ " boostdep [--track-sources] [--track-tests] --list-dependencies\n"
+ " boostdep --list-exceptions\n"
+ " boostdep --list-missing-headers\n"
+ " boostdep --list-buildable-dependencies\n"
+ "\n"
+ " boostdep [options] --module-overview\n"
+ " boostdep [options] --module-levels\n"
+ " boostdep [options] --module-weights\n"
+ "\n"
+ " boostdep [options] [--primary] <module>\n"
+ " boostdep [options] --secondary <module>\n"
+ " boostdep [options] --reverse <module>\n"
+ " boostdep [options] --subset <module>\n"
+ " boostdep [options] [--header] <header>\n"
+ " boostdep --test <module>\n"
+ " boostdep --cmake <module>\n"
+ " boostdep --pkgconfig <module> <version> [<var>=<value>] [<var>=<value>]...\n"
+ " boostdep [options] --subset-for <directory>\n"
+ "\n"
+ " [options]: [--boost-root <path-to-boost>]\n"
+ " [--[no-]track-sources] [--[no-]track-tests]\n"
+ " [--html-title <title>] [--html-footer <footer>]\n"
+ " [--html-stylesheet <stylesheet>] [--html-prefix <prefix>]\n"
+ " [--html]\n";
+
+ return -1;
+ }
+
+ bool root_set = false;
+
+ for( int i = 0; i < argc; ++i )
+ {
+ std::string option = argv[ i ];
+
+ if( option == "--boost-root" )
+ {
+ if( i + 1 < argc )
+ {
+ fs::path p( argv[ ++i ] );
+
+ if( is_boost_root( p ) )
+ {
+ fs::current_path( p );
+ root_set = true;
+ }
+ else
+ {
+ std::cerr << "'" << p.string() << "': not a valid Boost root.\n";
+ return -2;
+ }
+ }
+ else
+ {
+ std::cerr << "'" << option << "': missing argument.\n";
+ return -2;
+ }
+ }
+ }
+
+ if( !root_set && !find_boost_root() )
+ {
+ char const * env_root = std::getenv( "BOOST_ROOT" );
+
+ if( env_root && is_boost_root( env_root ) )
+ {
+ fs::current_path( env_root );
+ }
+ else
+ {
+ std::cerr << "boostdep: Could not find Boost root.\n";
+ return -2;
+ }
+ }
+
+ try
+ {
+ build_header_map();
+ }
+ catch( fs::filesystem_error const & x )
+ {
+ std::cerr << x.what() << std::endl;
+ }
+
+ bool html = false;
+ bool secondary = false;
+ bool track_sources = false;
+ bool track_tests = false;
+
+ std::string html_title = "Boost Dependency Report";
+ std::string html_footer;
+ std::string html_stylesheet;
+ std::string html_prefix;
+
+ std::ostringstream captured_output;
+ teebuf tsb( std::cout.rdbuf(), captured_output.rdbuf() );
+
+ save_cout_rdbuf scrdb;
+
+ for( int i = 1; i < argc; ++i )
+ {
+ std::string option = argv[ i ];
+
+ if( option == "--boost-root" )
+ {
+ ++i;
+ }
+ else if( option == "--list-modules" )
+ {
+ list_modules();
+ }
+ else if( option == "--list-buildable" )
+ {
+ list_buildable();
+ }
+ else if( option == "--title" || option == "--html-title" )
+ {
+ if( i + 1 < argc )
+ {
+ html_title = argv[ ++i ];
+ }
+ }
+ else if( option == "--footer" || option == "--html-footer" )
+ {
+ if( i + 1 < argc )
+ {
+ html_footer = argv[ ++i ];
+ }
+ }
+ else if( option == "--html-stylesheet" )
+ {
+ if( i + 1 < argc )
+ {
+ html_stylesheet = argv[ ++i ];
+ }
+ }
+ else if( option == "--html-prefix" )
+ {
+ if( i + 1 < argc )
+ {
+ html_prefix = argv[ ++i ];
+ }
+ }
+ else if( option == "--html" )
+ {
+ if( !html )
+ {
+ html = true;
+ output_html_header( html_title, html_stylesheet, html_prefix );
+ }
+ }
+ else if( option == "--track-sources" )
+ {
+ track_sources = true;
+ }
+ else if( option == "--no-track-sources" )
+ {
+ track_sources = false;
+ }
+ else if( option == "--track-tests" )
+ {
+ track_tests = true;
+ }
+ else if( option == "--no-track-tests" )
+ {
+ track_tests = false;
+ }
+ else if( option == "--primary" )
+ {
+ if( i + 1 < argc )
+ {
+ output_module_primary_report( argv[ ++i ], html, track_sources, track_tests );
+ }
+ }
+ else if( option == "--secondary" )
+ {
+ if( i + 1 < argc )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_module_secondary_report( argv[ ++i ], html );
+ }
+ }
+ else if( option == "--reverse" )
+ {
+ if( i + 1 < argc )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_module_reverse_report( argv[ ++i ], html );
+ }
+ }
+ else if( option == "--header" )
+ {
+ if( i + 1 < argc )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_header_report( argv[ ++i ], html );
+ }
+ }
+ else if( option == "--subset" )
+ {
+ if( i + 1 < argc )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_module_subset_report( argv[ ++i ], track_sources, track_tests, html );
+ }
+ }
+ else if( option == "--test" )
+ {
+ if( i + 1 < argc )
+ {
+ output_module_test_report( argv[ ++i ] );
+ }
+ }
+ else if( option == "--cmake" )
+ {
+ if( i + 1 < argc )
+ {
+ output_module_cmake_report( argv[ ++i ] );
+ }
+ }
+ else if( option == "--module-levels" )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_module_level_report( html );
+ }
+ else if( option == "--module-overview" )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_module_overview_report( html );
+ }
+ else if( option == "--module-weights" )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_module_weight_report( html );
+ }
+ else if( option == "--list-dependencies" )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ list_dependencies();
+ }
+ else if( option == "--list-exceptions" )
+ {
+ list_exceptions();
+ }
+ else if( option == "--list-missing-headers" )
+ {
+ list_missing_headers();
+ }
+ else if( option == "--pkgconfig" )
+ {
+ if( i + 2 < argc )
+ {
+ std::string module = argv[ ++i ];
+ std::string version = argv[ ++i ];
+
+ ++i;
+
+ output_pkgconfig( module, version, argc - i, argv + i );
+ }
+ else
+ {
+ std::cerr << "'" << option << "': missing module or version.\n";
+ }
+
+ break;
+ }
+ else if( option == "--subset-for" )
+ {
+ if( i + 1 < argc )
+ {
+ std::string module = argv[ ++i ];
+
+ enable_secondary( secondary, track_sources, track_tests );
+
+ std::set<std::string> headers;
+ add_module_headers( module, headers );
+
+ output_directory_subset_report( module, headers, html );
+ }
+ else
+ {
+ std::cerr << "'" << option << "': missing argument.\n";
+ }
+
+ break;
+ }
+ else if( option == "--list-buildable-dependencies" )
+ {
+ enable_secondary( secondary, true, false );
+ list_buildable_dependencies();
+ }
+ else if( option == "--capture-output" )
+ {
+ std::cout.rdbuf( &tsb );
+ }
+ else if( option == "--compare-output" )
+ {
+ if( i + 1 < argc )
+ {
+ std::string fn = argv[ ++i ];
+ std::fstream is( fn.c_str() );
+
+ if( !is )
+ {
+ std::cerr << option << " '" << fn << "': could not open file.\n";
+ return 1;
+ }
+
+ std::istreambuf_iterator<char> first( is ), last;
+ std::string fc( first, last );
+
+ if( fc != captured_output.str() )
+ {
+ std::cerr << option << " '" << fn << "': output does not match; expected output:\n---\n" << fc << "---\n";
+ return 1;
+ }
+
+ std::cerr << option << " '" << fn << "': output matches.\n";
+ captured_output.str( "" );
+ }
+ else
+ {
+ std::cerr << "'" << option << "': missing argument.\n";
+ return 1;
+ }
+ }
+ else if( s_modules.count( option ) )
+ {
+ output_module_primary_report( option, html, track_sources, track_tests );
+ }
+ else if( s_header_map.count( option ) )
+ {
+ enable_secondary( secondary, track_sources, track_tests );
+ output_header_report( option, html );
+ }
+ else
+ {
+ std::cerr << "'" << option << "': not an option, module or header.\n";
+ }
+ }
+
+ if( html )
+ {
+ output_html_footer( html_footer );
+ }
+}
diff --git a/src/boost/tools/boostdep/test/Jamfile b/src/boost/tools/boostdep/test/Jamfile
new file mode 100644
index 000000000..7695ca825
--- /dev/null
+++ b/src/boost/tools/boostdep/test/Jamfile
@@ -0,0 +1,12 @@
+# Copyright 2017 Peter Dimov
+#
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+import testing ;
+
+path-constant ROOT : ../../.. ;
+path-constant HERE : . ;
+
+run ../src/boostdep.cpp /boost//filesystem : --boost-root $(ROOT) --capture-output assert --compare-output $(HERE)/assert-primary.txt : : : assert-primary ;
+run ../src/boostdep.cpp /boost//filesystem : --boost-root $(ROOT) --capture-output --secondary bind --compare-output $(HERE)/bind-secondary.txt : : : bind-secondary ;
diff --git a/src/boost/tools/boostdep/test/assert-primary.txt b/src/boost/tools/boostdep/test/assert-primary.txt
new file mode 100644
index 000000000..00d53e8a3
--- /dev/null
+++ b/src/boost/tools/boostdep/test/assert-primary.txt
@@ -0,0 +1,9 @@
+Primary dependencies for assert:
+
+config:
+ <boost/config.hpp>
+ from <boost/assert.hpp>
+ from <boost/assert/source_location.hpp>
+ <boost/cstdint.hpp>
+ from <boost/assert/source_location.hpp>
+
diff --git a/src/boost/tools/boostdep/test/bind-secondary.txt b/src/boost/tools/boostdep/test/bind-secondary.txt
new file mode 100644
index 000000000..959936cfb
--- /dev/null
+++ b/src/boost/tools/boostdep/test/bind-secondary.txt
@@ -0,0 +1,5 @@
+Secondary dependencies for bind:
+
+core:
+ adds assert
+
diff --git a/src/boost/tools/boostdep/test/utf8-test.zip b/src/boost/tools/boostdep/test/utf8-test.zip
new file mode 100644
index 000000000..634b62530
--- /dev/null
+++ b/src/boost/tools/boostdep/test/utf8-test.zip
Binary files differ