diff options
Diffstat (limited to '')
-rw-r--r-- | src/boost/tools/boostdep/CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/boost/tools/boostdep/README.md | 4 | ||||
-rw-r--r-- | src/boost/tools/boostdep/build/Jamfile | 11 | ||||
-rw-r--r-- | src/boost/tools/boostdep/depinst/depinst.py | 282 | ||||
-rw-r--r-- | src/boost/tools/boostdep/depinst/exceptions.txt | 396 | ||||
-rw-r--r-- | src/boost/tools/boostdep/examples/report.bat | 39 | ||||
-rw-r--r-- | src/boost/tools/boostdep/examples/report.css | 24 | ||||
-rw-r--r-- | src/boost/tools/boostdep/src/boostdep.cpp | 3005 | ||||
-rw-r--r-- | src/boost/tools/boostdep/test/Jamfile | 12 | ||||
-rw-r--r-- | src/boost/tools/boostdep/test/assert-primary.txt | 9 | ||||
-rw-r--r-- | src/boost/tools/boostdep/test/bind-secondary.txt | 5 | ||||
-rw-r--r-- | src/boost/tools/boostdep/test/utf8-test.zip | bin | 0 -> 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><" << header << "></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><" << header << "></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><" << header << "></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><" << header << "></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><" << header << "></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><" << header << "></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 << " ⇢ "; + } + + 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 Binary files differnew file mode 100644 index 000000000..634b62530 --- /dev/null +++ b/src/boost/tools/boostdep/test/utf8-test.zip |