$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r73432 - in sandbox/tools/profile_templates2: . doc
From: dsaritz_at_[hidden]
Date: 2011-07-29 11:25:05
Author: psiha
Date: 2011-07-29 11:25:04 EDT (Fri, 29 Jul 2011)
New Revision: 73432
URL: http://svn.boost.org/trac/boost/changeset/73432
Log:
Added a basic readme.
Reimplemented preprocess.pl in C++ with Xpressive.
Replaced the main BB jam file with a CMake module.
Added:
   sandbox/tools/profile_templates2/doc/readme.txt   (contents, props changed)
   sandbox/tools/profile_templates2/preprocess.cpp
      - copied, changed from r73430, /sandbox/tools/profile_templates2/preprocess.pl
   sandbox/tools/profile_templates2/profiler.cmake   (contents, props changed)
Removed:
   sandbox/tools/profile_templates2/preprocess.pl
   sandbox/tools/profile_templates2/template-profile.jam
Text files modified: 
   sandbox/tools/profile_templates2/preprocess.cpp |   258 +++++++++++++++++++++++++++++++-------- 
   1 files changed, 202 insertions(+), 56 deletions(-)
Added: sandbox/tools/profile_templates2/doc/readme.txt
==============================================================================
--- (empty file)
+++ sandbox/tools/profile_templates2/doc/readme.txt	2011-07-29 11:25:04 EDT (Fri, 29 Jul 2011)
@@ -0,0 +1,7 @@
+A rework of the SW's original with the following goals:
+ - remove dependencies on Perl and a built Boost (Regex) by moving to Boost.Xpressive and later to Boost.Spirit
+ - further improve performance (e.g. low level C IO and memory mapped files instead of C++ streams)
+ - convert to a single standalone binary
+ - move to CMake and support for creating profiling targets in user projects/solutions.
+ 
+ (...work in progress...)
\ No newline at end of file
Copied: sandbox/tools/profile_templates2/preprocess.cpp (from r73430, /sandbox/tools/profile_templates2/preprocess.pl)
==============================================================================
--- /sandbox/tools/profile_templates2/preprocess.pl	(original)
+++ sandbox/tools/profile_templates2/preprocess.cpp	2011-07-29 11:25:04 EDT (Fri, 29 Jul 2011)
@@ -1,60 +1,206 @@
-# preprocess.pl
-#
-# Copyright (c) 2008-2009
-# Steven Watanabe
-#
-# 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)
-
-#add "~" to the end of the backup file name
-$^I = "~";
-
-#read the whole file at once
-undef $/;
-use re 'eval' ;
-
-$backslashed_lines = qr/(?>(?>\\(?>\n|\r\n)|.)*)/;
-$string = qr/(?>\"(?>\\\\|\\\"|[^\"])*\"|'(?>\\\\|\\'|[^'])*')/;
-$comment = qr{(?>//$backslashed_lines|/\*(?>[^*]|\*(?!/))*\*/)};
-$pp = qr/(?>#$backslashed_lines)/;
-$ignored = qr/(?>$string|$comment|$pp)/;
-$parens = qr/(?>\((?>(?>(?>$ignored|[^()])+)|(??{$parens}))*\))/;
-$ws = qr/(?:$comment|$pp|\s|(?:\\(?:\n|\r\n)))/;
-
-$class_header = qr/(?>(?>\b(?:class|struct))(?>$ws+\w+)(?>(?>[^(){;=]|$parens|$ignored)*)\{)/;
-
-$control = qr/(?:\b(?:__attribute__|__if_exists|__if_not_exists|for|while|if|catch|switch)\b)/;
-$modifiers = qr/(?:\b(?:try|const|volatile)\b)/;
-$start = qr/(?:^|\G|(?<=[{};]))(?>$ws*)/;
-$body = qr/(?:(?!$control)(?>$ignored|[^{};]))/;
-$end = qr/(?:$parens|\])/;
-$body_start = qr/(?>$ws*(?:$modifiers$ws*)*\{)/;
-
-$function_header = qr/(?>(?:$start)(?:$body*?$end)(?:$body_start))/;
-
-_at_braces = ();
-
-sub process {
-    my $header = $_[0];
-    my $open_brace = $_[1];
-    my $close_brace = $_[2];
-
-    if($header) {
-        push(@braces, " TEMPLATE_PROFILE_EXIT() }");
-        return("$header TEMPLATE_PROFILE_ENTER()");
-    } elsif($open_brace) {
-        push(@braces, "}");
-        return($open_brace);
-    } elsif($close_brace) {
-        return(pop(@braces));
-    } else {
-        die("This should only be called if the pattern matched: \$$_[0],$_[1],$_[2],$_[3],\$");
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \file preprocess.cpp
+/// --------------------
+///
+/// Copyright (c) 2008.-2009. Steven Watanabe (preprocess.pl)
+/// Copyright (c) 2011.       Domagoj Saric
+///
+///  Use, modification and distribution is subject to 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)
+///
+/// For more information, see http://www.boost.org
+///
+////////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------
+#undef BOOST_ENABLE_ASSERT_HANDLER
+
+#define BOOST_XPRESSIVE_USE_C_TRAITS
+
+#include "boost/assert.hpp"
+#include "boost/concept_check.hpp"
+#include "boost/interprocess/file_mapping.hpp"
+#include "boost/interprocess/mapped_region.hpp"
+#include "boost/range/iterator_range_core.hpp"
+#include "boost/xpressive/xpressive.hpp"
+
+#include <cassert>
+#include <iterator>
+#include <iostream>
+#include <fstream>
+//------------------------------------------------------------------------------
+
+namespace regex
+{
+    using namespace boost::xpressive;
+
+    cregex make_parens()
+    {
+        cregex parens;// parens      = keep( '(' >> *keep( keep( +keep( ignored | ~(set= '(',')') ) | ( -!by_ref( parens ) ) ) ) >> ')' );
+        parens =
+        '('                            // is an opening parenthesis ...
+         >>                           // followed by ...
+          *(                          // zero or more ...
+             keep( +~(set='(',')') )  // of a bunch of things that are not parentheses ...
+           |                          // or ...
+             by_ref(parens)      // a balanced set of parentheses
+           )                          //   (ooh, recursion!) ...
+         >>                           // followed by ...
+        ')'                            // a closing parenthesis
+        ;
+        return parens;
     }
+    
+    cregex const backslashed_lines = keep( keep( *( '\\' >> keep( _ln ) | _ ) ) );
+    cregex const string            = cregex::compile( "(?>\"(?>\\\\|\\\"|[^\"])*\"|'(?>\\\\|\\'|[^'])*')" );
+    cregex const comment           = keep( "//" >> backslashed_lines | "/*" >> keep( *( ~(set='*') | '*' >> ~before('/') ) ) >> "*/" );
+    cregex const pp                = keep( '#' >> backslashed_lines );
+    cregex const ignored           = keep( string | comment | pp );
+    cregex const parens            = make_parens();
+    cregex const ws                = comment | pp | _s | _ln;
+
+    cregex const class_header = keep( keep( _b >> ( as_xpr( "class" ) | "struct" ) ) >> keep( +ws >> +_w ) >> keep( *keep( ~(set= '(',')','{',';','=') | parens | ignored ) ) >> '{' );
+
+    cregex const control    = ( _b >> ( as_xpr( "__attribute__" ) | "__if_exists" | "__if_not_exists" | "for" | "while" | "if" | "catch" | "switch" ) >> _b );
+    cregex const modifiers  = ( _b >> ( as_xpr( "try" ) | "const" | "volatile" ) >> _b );
+    cregex const start      = ( bos /*| cregex::compile( "\\G" )*/ | after( (set= '{','}',';') ) ) >> keep( *ws );
+    cregex const body       = ~before( control ) >> keep( ignored | ~(set= '{','}',';') );
+    cregex const end        = parens | ']';
+    cregex const body_start = keep( *ws >> *(modifiers >> *ws) >> '{' );
+
+    cregex const function_header = keep( start >> ( *body >> end ) >> body_start );
 }
 
-while(<>) {
-    s/(($ignored)|((?>$class_header|$function_header))|([{])|([}]))/$2?$2:process($3,$4,$5)/ge;
-    print "#include <template_profiler.hpp>\n";
-    print;
+struct formatter : boost::noncopyable
+{
+    template<typename Out>
+    Out operator()( regex::cmatch const & what, Out out ) const
+    {
+        using namespace regex;
+
+        typedef cmatch::value_type sub_match;
+
+        BOOST_ASSERT( what.size() == 5 );
+
+        cmatch::const_iterator const p_match( std::find_if( what.begin() + 1, what.end(), []( sub_match const & match ){ return match.matched; } ) );
+        BOOST_ASSERT_MSG( p_match != what.end(), "Something should have matched." );
+        sub_match const & match( *p_match );
+
+        enum match_type_t
+        {
+            ignore = 1,
+            header,
+            open_brace,
+            close_brace
+        };
+
+        unsigned int const match_type( p_match - what.begin() );
+        switch ( match_type )
+        {
+            case ignore:
+                out = std::copy( match.first, match.second, out );
+                break;
+
+            case header:
+            {
+                braces.push_back( " TEMPLATE_PROFILE_EXIT() }" );
+                static char const tail[] = " TEMPLATE_PROFILE_ENTER()";
+                out = std::copy( match.first      , match.second       , out );
+                out = std::copy( boost::begin( tail ), boost::end( tail ) - 1, out );
+                break;
+            }
+
+            case open_brace:
+                braces.push_back( "}" );
+                out = std::copy( match.first, match.second, out );
+                break;
+
+            case close_brace:
+                out = std::copy( braces.back().begin(), braces.back().end(), out );
+                braces.pop_back();
+                break;
+
+            default:
+                BOOST_ASSERT( false );
+                break;
+        }
+
+        if ( match_type != header )
+        {
+            //...zzz...definitions where the opening brace is on the next line are not getting caught...
+            static char const class_ [] = "class";
+            static char const struct_[] = "struct";
+            BOOST_ASSERT( std::find_end( match.first, match.second, boost::begin( class_  ), boost::end( class_  ) - 1 ) == match.second );
+            BOOST_ASSERT( std::find_end( match.first, match.second, boost::begin( struct_ ), boost::end( struct_ ) - 1 ) == match.second );
+            std::string const mstr( match.str() );
+            BOOST_ASSERT( !std::strstr( mstr.c_str(), class_ ) );
+            BOOST_ASSERT( !std::strstr( mstr.c_str(), struct_ ) );
+        }
+
+        return out;
+    }
+
+    mutable std::vector<std::string> braces;
+};
+
+
+int main( int const argc, char * * const argv )
+{
+    if ( argc != 2 )
+        return EXIT_FAILURE;
+
+    try
+    {
+        using namespace boost;
+
+        interprocess::mapped_region const input_file_view
+        (
+            interprocess::file_mapping
+            (
+                argv[ 1 ],
+                interprocess::read_only
+            ),
+            interprocess::read_only
+        );
+
+        iterator_range<char const *> input
+        (
+            static_cast<char const *>( input_file_view.get_address() ),
+            static_cast<char const *>( input_file_view.get_address() ) + input_file_view.get_size()
+        );
+
+        using namespace regex;
+        cregex const main_regex( (s1= ignored) | (s2=keep( class_header | function_header )) | (s3='{') | (s4='}') );
+        match_results<char const *> search_results;
+
+        std::ofstream output( "preprocessed.cpp" );
+        output << "#include <template_profiler.hpp>\n" << std::endl;
+        std::ostream_iterator<char> out_iter( output );
+
+        formatter fmt;
+
+        while ( input.begin() < input.end() )
+        {
+            char const * /*const*/ p_endl( std::find( input.begin(), input.end(), '\n' ) );
+            std::size_t const line_length( p_endl - input.begin() );
+
+            out_iter = regex_replace( out_iter, input.begin(), p_endl, main_regex, fmt );
+
+            *out_iter++ = *p_endl++;
+            input = iterator_range<char const *>( p_endl, input.end() );
+        }
+
+        return EXIT_SUCCESS;
+    }
+    catch ( std::exception const & e )
+    {
+        std::puts( e.what() );
+        return EXIT_FAILURE;
+    }
+    catch ( ... )
+    {
+        return EXIT_FAILURE;
+    }
 }
Deleted: sandbox/tools/profile_templates2/preprocess.pl
==============================================================================
--- sandbox/tools/profile_templates2/preprocess.pl	2011-07-29 11:25:04 EDT (Fri, 29 Jul 2011)
+++ (empty file)
@@ -1,60 +0,0 @@
-# preprocess.pl
-#
-# Copyright (c) 2008-2009
-# Steven Watanabe
-#
-# 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)
-
-#add "~" to the end of the backup file name
-$^I = "~";
-
-#read the whole file at once
-undef $/;
-use re 'eval' ;
-
-$backslashed_lines = qr/(?>(?>\\(?>\n|\r\n)|.)*)/;
-$string = qr/(?>\"(?>\\\\|\\\"|[^\"])*\"|'(?>\\\\|\\'|[^'])*')/;
-$comment = qr{(?>//$backslashed_lines|/\*(?>[^*]|\*(?!/))*\*/)};
-$pp = qr/(?>#$backslashed_lines)/;
-$ignored = qr/(?>$string|$comment|$pp)/;
-$parens = qr/(?>\((?>(?>(?>$ignored|[^()])+)|(??{$parens}))*\))/;
-$ws = qr/(?:$comment|$pp|\s|(?:\\(?:\n|\r\n)))/;
-
-$class_header = qr/(?>(?>\b(?:class|struct))(?>$ws+\w+)(?>(?>[^(){;=]|$parens|$ignored)*)\{)/;
-
-$control = qr/(?:\b(?:__attribute__|__if_exists|__if_not_exists|for|while|if|catch|switch)\b)/;
-$modifiers = qr/(?:\b(?:try|const|volatile)\b)/;
-$start = qr/(?:^|\G|(?<=[{};]))(?>$ws*)/;
-$body = qr/(?:(?!$control)(?>$ignored|[^{};]))/;
-$end = qr/(?:$parens|\])/;
-$body_start = qr/(?>$ws*(?:$modifiers$ws*)*\{)/;
-
-$function_header = qr/(?>(?:$start)(?:$body*?$end)(?:$body_start))/;
-
-_at_braces = ();
-
-sub process {
-    my $header = $_[0];
-    my $open_brace = $_[1];
-    my $close_brace = $_[2];
-
-    if($header) {
-        push(@braces, " TEMPLATE_PROFILE_EXIT() }");
-        return("$header TEMPLATE_PROFILE_ENTER()");
-    } elsif($open_brace) {
-        push(@braces, "}");
-        return($open_brace);
-    } elsif($close_brace) {
-        return(pop(@braces));
-    } else {
-        die("This should only be called if the pattern matched: \$$_[0],$_[1],$_[2],$_[3],\$");
-    }
-}
-
-while(<>) {
-    s/(($ignored)|((?>$class_header|$function_header))|([{])|([}]))/$2?$2:process($3,$4,$5)/ge;
-    print "#include <template_profiler.hpp>\n";
-    print;
-}
Added: sandbox/tools/profile_templates2/profiler.cmake
==============================================================================
--- (empty file)
+++ sandbox/tools/profile_templates2/profiler.cmake	2011-07-29 11:25:04 EDT (Fri, 29 Jul 2011)
@@ -0,0 +1,64 @@
+################################################################################
+#         Copyright 2003 & onward LASMEA UMR 6602 CNRS/Univ. Clermont II
+#         Copyright 2009 & onward LRI    UMR 8623 CNRS/Univ Paris Sud XI
+#         Copyright 2011 & onward Domagoj Saric
+#
+#   Based on the original from the NT2 library.
+#   (https://github.com/MetaScale/nt2)
+#
+#          Distributed under the Boost Software License, Version 1.0.
+#                 See accompanying file LICENSE.txt or copy at
+#                     http://www.boost.org/LICENSE_1_0.txt
+################################################################################
+
+################################################################################
+# Add the target to build filter and postprocess
+################################################################################
+FIND_FILE(PROFILER_PATH profiler ${CMAKE_MODULE_PATH})
+
+ADD_EXECUTABLE(template.profiler.filter ${PROFILER_PATH}/filter.cpp)
+set_property(TARGET template.profiler.filter PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/tools)
+
+INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
+ADD_EXECUTABLE(template.profiler.postprocess ${PROFILER_PATH}/postprocess.cpp)
+if (NOT MSVC)
+    target_link_libraries(template.profiler.postprocess ${Boost_LIBRARIES})
+endif()
+set_property(TARGET template.profiler.postprocess PROPERTY RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/tools)
+
+################################################################################
+# Make a function to compile foo and profile it
+################################################################################
+function(template_profile target src)
+  if(CMAKE_GENERATOR MATCHES "Make")
+    set( profiler_cxx_flags ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} )
+  else()
+    set( profiler_cxx_flags ${CMAKE_CXX_FLAGS_DEBUG} )
+  endif() 
+
+  get_directory_property( preprocessor_definitions COMPILE_DEFINITIONS )
+  foreach(preprocessor_definition ${preprocessor_definitions})
+    list(APPEND profiler_cxx_flags -D${preprocessor_definition})
+  endforeach()
+
+  get_directory_property(INCLUDES INCLUDE_DIRECTORIES)
+  foreach(INCLUDE ${INCLUDES})
+    list(APPEND INCLUDE_DIRECTORIES -I"${INCLUDE}")
+  endforeach()
+  
+  add_custom_command(OUTPUT ${target}.preprocessed.cpp
+                     COMMAND ${CMAKE_CXX_COMPILER} ${profiler_cxx_flags} ${INCLUDE_DIRECTORIES} -E ${CMAKE_CURRENT_SOURCE_DIR}/${src}
+                           | ${PERL_EXECUTABLE} ${PROFILER_PATH}/preprocess.pl > ${target}.preprocessed.cpp
+                     DEPENDS ${src}
+                   )
+  add_custom_command(OUTPUT ${target}.template_profile
+                     COMMAND ${CMAKE_CXX_COMPILER} ${profiler_cxx_flags} -I${PROFILER_PATH} ${INCLUDE_DIRECTORIES} -c -DPROFILE_TEMPLATES ${target}.preprocessed.cpp 2>&1
+                           | \"${PROJECT_BINARY_DIR}/tools/${CMAKE_CFG_INTDIR}/template.profiler.filter\" ${ARGN} > ${target}.filtered && \"${PROJECT_BINARY_DIR}/tools/${CMAKE_CFG_INTDIR}/template.profiler.postprocess\" ${ARGN} ${target}.filtered > ${target}.template_profile
+                     DEPENDS ${target}.preprocessed.cpp
+                             template.profiler.filter
+                             template.profiler.postprocess 
+                    )
+  add_custom_target (${target}
+                     DEPENDS ${target}.template_profile
+                    )
+endfunction()
Deleted: sandbox/tools/profile_templates2/template-profile.jam
==============================================================================
--- sandbox/tools/profile_templates2/template-profile.jam	2011-07-29 11:25:04 EDT (Fri, 29 Jul 2011)
+++ (empty file)
@@ -1,178 +0,0 @@
-# template-profile.jam
-#
-# Copyright (c) 2008
-# Steven Watanabe
-#
-# 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)
-
-import feature ;
-import toolset ;
-import type ;
-import errors ;
-import path ;
-import modules ;
-import generators ;
-import "class" ;
-
-module-location = [ path.parent [ path.make [ modules.binding template-profile ] ] ] ;
-
-INSTRUMENT-ACTION = [ path.native [ path.join $(module-location) preprocess.pl ] ] ;
-INSTRUMENT-ACTION = perl \"$(INSTRUMENT-ACTION)\" ;
-
-type.register INSTRUMENTED_TEMPLATE_PREPROCESSED_CPP : : CPP ;
-type.register RAW_TEMPLATE_PROFILE : rtp ;
-type.register TEMPLATE_PROFILE : template-profile ;
-
-feature.feature <template-profile-toolset> : msvc gcc : free ;
-feature.feature <template-profile-filter> : : path incidental ;
-feature.feature <flat-profile> : on off : incidental propagated ;
-feature.feature <call-graph> : on off : incidental propagated ;
-
-rule init-toolset ( toolset ) {
-    toolset.flags $(toolset).compile.c++.preprocess INSTRUMENT-ACTION : $(INSTRUMENT-ACTION) : unchecked ;
-    toolset.flags $(toolset).compile.c++.template-profile FILTER <template-profile-filter> : : unchecked ;
-    toolset.flags $(toolset).compile.c++.template-profile FILTER-OPTIONS <call-graph>on : --call-graph : unchecked ;
-    generators.register-c-compiler $(toolset).compile.c++.preprocess : CPP : INSTRUMENTED_TEMPLATE_PREPROCESSED_CPP : <toolset>$(toolset) ;
-}
-
-module gcc {
-
-    import template-profile : init-toolset ;
-
-    template-profile.init-toolset gcc ;
-
-    actions compile.c++.preprocess {
-        $(CONFIG_COMMAND) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -E "$(>)" | $(INSTRUMENT-ACTION) >"$(<)"
-    }
-
-    actions compile.c++.template-profile {
-        "$(CONFIG_COMMAND)" $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -D PROFILE_TEMPLATES -I"$(INCLUDES)" -c "$(>:W)" 2>&1 | "$(FILTER)" $(FILTER-OPTIONS) >"$(<)"
-    }
-
-}
-
-module msvc {
-
-    import template-profile : init-toolset ;
-    template-profile.init-toolset msvc ;
-
-    actions compile.c++.preprocess {
-        $(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(lang-opt) -U$(UNDEFS) $(CFLAGS) $(C++FLAGS) $(OPTIONS) $(.nl)-D$(DEFINES) $(.nl)"-I$(INCLUDES:W)")" | $(INSTRUMENT-ACTION) >"$(<[1]:W)"
-    }
-
-    actions compile.c++.template-profile {
-        $(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -c $(lang-opt) -U$(UNDEFS) $(CFLAGS) $(C++FLAGS) $(OPTIONS) -W4 $(.nl)-D$(DEFINES) -D PROFILE_TEMPLATES $(.nl)"-I$(INCLUDES:W)")" 2>&1 | "$(FILTER)" $(FILTER-OPTIONS) >"$(<)"
-    }
-
-}
-
-class warn-generator : generator {
-
-    import template-profile ;
-    import targets ;
-    import path ;
-    import modules ;
-
-    rule __init__ ( * : * ) {
-        generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
-    }
-    rule run ( project name : properties : sources * : multiple ? ) {
-        local toolset = [ $(properties).get <toolset> ] ;
-        if ! $(toolset) {
-            errors.error "No toolset specified" ;
-        }
-        switch $(toolset) {
-            case msvc* :
-                toolset = msvc ;
-            case gcc* :
-                toolset = gcc ;
-            case * :
-                errors.error unrecognized toolset $(toolset) ;
-        }
-        local self-dir = [ modules.peek template-profile : module-location ] ;
-
-        current_path = [ modules.peek template-profile : module-location ] ;
-        local filter-main-target = [ targets.resolve-reference [ path.join $(current_path) src ] : $(project) ] ;
-        filter-main-target = [ $(filter-main-target[1]).main-target filter ] ;
-        local filter-binary-dependencies = [ $(filter-main-target).generate [ $(properties).propagated ] ] ;
-        filter-binary-dependencies = $(filter-binary-dependencies[2-]) ;
-        local filter-binary = ;
-
-        for local target in $(filter-binary-dependencies) {
-            if [ $(target).type ] = EXE {
-                filter-binary = 
-                    [ path.native 
-                        [ path.join
-                            [ $(target).path ]
-                            [ $(target).name ]
-                        ]
-                    ] ;
-            }
-        }
-
-        if ! $(filter-binary) {
-            errors.error Could not find filter binary ;
-        }
-
-        local new-properties = [ $(properties).add-raw <dependency>$(filter-binary-dependencies) <template-profile-filter>$(filter-binary) <include>$(self-dir) ] ;
-
-        return [ generator.run $(project) $(name) : $(new-properties)  : $(sources) : $(multiple) ] ;
-    }
-}
-
-generators.register [ class.new warn-generator msvc.compile.c++.template-profile : INSTRUMENTED_TEMPLATE_PREPROCESSED_CPP : RAW_TEMPLATE_PROFILE : <toolset>msvc ] ;
-generators.register [ class.new warn-generator gcc.compile.c++.template-profile : INSTRUMENTED_TEMPLATE_PREPROCESSED_CPP : RAW_TEMPLATE_PROFILE : <toolset>gcc ] ;
-
-class final-profile-generator : generator {
-
-    import targets ;
-    import template-profile ;
-    import path ;
-    import modules ;
-
-    rule __init__ ( ) {
-        generator.__init__ template-profile.process-raw-profile : RAW_TEMPLATE_PROFILE : TEMPLATE_PROFILE ;
-    }
-    rule run ( project name : properties : sources * : multiple ? ) {
-
-        current_path = [ modules.peek template-profile : module-location ] ;
-
-        local postprocess-main-target = [ targets.resolve-reference [ path.join $(current_path) src ] : $(project) ] ;
-        postprocess-main-target = [ $(postprocess-main-target[1]).main-target postprocess ] ;
-        local postprocess-binary-dependencies = [ $(postprocess-main-target).generate [ $(properties).propagated ] ] ;
-        postprocess-binary-dependencies = $(postprocess-binary-dependencies[2-]) ;
-        local postprocess-binary = ;
-
-        for local target in $(postprocess-binary-dependencies) {
-            if [ $(target).type ] = EXE {
-                postprocess-binary = 
-                    [ path.native 
-                        [ path.join
-                            [ $(target).path ]
-                            [ $(target).name ]
-                        ]
-                    ] ;
-            }
-        }
-
-        if ! $(postprocess-binary) {
-            errors.error Could not find postprocessor binary ;
-        }
-
-        local new-properties = [ $(properties).add-raw <dependency>$(postprocess-binary-dependencies) <postprocess-binary>$(postprocess-binary) ] ;
-        return [ generator.run $(project) $(name) : $(new-properties) : $(sources) : $(multiple) ] ;
-    }
-}
-
-generators.register [ class.new final-profile-generator ] ;
-
-feature.feature <postprocess-binary> : : path incidental ;
-
-toolset.flags template-profile.process-raw-profile POSTPROCESS-BINARY <postprocess-binary> ;
-toolset.flags template-profile.process-raw-profile POSTPROCESS-OPTIONS <call-graph>on : --call-graph ;
-
-actions process-raw-profile {
-    "$(POSTPROCESS-BINARY)" $(POSTPROCESS-OPTIONS) "$(>)" >"$(<)"
-}