Browse Source

Merged in additions from serialization_next_release branch to support validation of one's current boost installation on a either a library by library or global basis

[SVN r38800]
Robert Ramey 18 years ago
parent
commit
2a7750360a

+ 11 - 0
tools/regression/build/Jamfile.v2

@@ -18,10 +18,20 @@ exe compiler_status
     release
     ;
 
+exe library_status
+    :
+    ../library_status.cpp ../detail/tiny_xml.cpp
+    /boost/filesystem//boost_filesystem
+    :
+    :
+    release
+    ;
+
 install dist-bin
     :
     process_jam_log
     compiler_status
+    library_status
     :
     <install-type>EXE
     <location>../../../dist/bin
@@ -33,6 +43,7 @@ install dist-lib
     :
     process_jam_log
     compiler_status
+    library_status
     :
     <install-type>LIB
     <location>../../../dist/lib

+ 59 - 0
tools/regression/build/vcide/compiler_status.vcproj

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="compiler_status"
+	ProjectGUID="{81F22EF9-A1B8-46CB-9C2D-56FD4327B942}"
+	Keyword="MakeFileProj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd ..\..\..\..\tools\regression\build
+..\..\jam\src\bin.ntx86\bjam.exe compiler_status.exe variant=debug"
+				ReBuildCommandLine="cd ..\..\..\..\tools\regression\build
+...\..\jam\src\bin.ntx86\bjam.exe -a compiler_status.exe variant=debug"
+				CleanCommandLine="cd ..\..\..\..\tools\regression\build
+call bjam --v2 msvc-7.1 debug clean
+"
+				Output="compiler_status.exe"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam compiler_status variant=release link=static"
+				ReBuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam -a compiler_status variant=release link=static"
+				CleanCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam clean"
+				Output="..\..\..\..\bin.v2\tools\regression\build\msvc-7.1\release\link-static\compiler_status.exe"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\..\compiler_status.cpp">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 64 - 0
tools/regression/build/vcide/library_status.vcproj

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="library_status"
+	ProjectGUID="{465BDB84-92B5-4C60-AF26-8BD1A61A089E}"
+	Keyword="MakeFileProj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam library_status variant=debug link=static"
+				ReBuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam -a library_status variant=debug link=static"
+				CleanCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam clean"
+				Output="..\..\..\..\bin.v2\tools\regression\build\msvc-7.1\debug\link-static\library_status.exe"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam library_status variant=release link=static"
+				ReBuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam -a library_status variant=release link=static"
+				CleanCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam clean"
+				Output="..\..\..\..\bin.v2\tools\regression\build\msvc-7.1\release\link-static\library_status.exe"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath="..\..\library_status.cpp">
+			</File>
+			<File
+				RelativePath="..\..\detail\tiny_xml.cpp">
+			</File>
+			<File
+				RelativePath="..\..\detail\tiny_xml.hpp">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 72 - 68
tools/regression/build/vcide/process_jam_log.vcproj

@@ -1,68 +1,72 @@
-<?xml version="1.0" encoding="windows-1251"?>
-<VisualStudioProject
-	ProjectType="Visual C++"
-	Version="7.10"
-	Name="process_jam_log"
-	ProjectGUID="{9A751791-929F-496A-8DE7-B61020619BFA}"
-	RootNamespace="process_jam_log"
-	Keyword="MakeFileProj">
-	<Platforms>
-		<Platform
-			Name="Win32"/>
-	</Platforms>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="0">
-			<Tool
-				Name="VCNMakeTool"
-				BuildCommandLine="cd ..\..\..\..\tools\regression\build
-bjam --v2 msvc-7.1 debug
-"
-				ReBuildCommandLine="cd ..\..\..\..\tools\regression\build
-call bjam --v2 msvc-7.1 debug clean
-call bjam --v2 msvc-7.1 debug"
-				CleanCommandLine="cd ..\..\..\..\tools\regression\build
-call bjam --v2 msvc-7.1 debug clean
-"
-				Output="process_jam_log.exe"/>
-		</Configuration>
-		<Configuration
-			Name="Release|Win32"
-			OutputDirectory="Release"
-			IntermediateDirectory="Release"
-			ConfigurationType="0">
-			<Tool
-				Name="VCNMakeTool"
-				BuildCommandLine="cd C:\users\misha\Stuff\boost\boost\tools\regression\build"
-				ReBuildCommandLine="cd C:\users\misha\Stuff\boost\boost\tools\regression\build"
-				Output="process_jam_log.exe"/>
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Source Files"
-			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
-		</Filter>
-		<Filter
-			Name="Header Files"
-			Filter="h;hpp;hxx;hm;inl;inc;xsd"
-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
-		</Filter>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
-		</Filter>
-		<File
-			RelativePath=".\readme.txt">
-		</File>
-	</Files>
-	<Globals>
-	</Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="process_jam_log"
+	ProjectGUID="{9A751791-929F-496A-8DE7-B61020619BFA}"
+	RootNamespace="process_jam_log"
+	Keyword="MakeFileProj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd ..\..\..\..\tools\regression\build
+..\..\jam\src\bin.ntx86\bjam.exe process_jam_log variant=debug
+"
+				ReBuildCommandLine="cd ..\..\..\..\tools\regression\build
+call bjam --v2 msvc-7.1 debug clean
+call bjam --v2 msvc-7.1 debug"
+				CleanCommandLine="cd ..\..\..\..\tools\regression\build
+call bjam --v2 msvc-7.1 debug clean
+"
+				Output="../../../../bin.v2/tools/regression/build/msvc-7.1/debug/link-static/process_jam_log.exe"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="0">
+			<Tool
+				Name="VCNMakeTool"
+				BuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam process_jam_log variant=release link=static"
+				ReBuildCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam -a process_jam_log variant=release link=static"
+				CleanCommandLine="cd ..
+..\..\jam\src\bin.ntx86\bjam clean"
+				Output="..\..\..\..\bin.v2\tools\regression\build\msvc-7.1\release\link-static\process_jam_log.exe"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+		</Filter>
+		<File
+			RelativePath=".\readme.txt">
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

+ 37 - 0
tools/regression/build/vcide/regression.sln

@@ -0,0 +1,37 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "compiler_status", "compiler_status.vcproj", "{81F22EF9-A1B8-46CB-9C2D-56FD4327B942}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "process_jam_log", "process_jam_log.vcproj", "{9A751791-929F-496A-8DE7-B61020619BFA}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "library_status", "library_status.vcproj", "{465BDB84-92B5-4C60-AF26-8BD1A61A089E}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfiguration) = preSolution
+		Debug = Debug
+		Release = Release
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{81F22EF9-A1B8-46CB-9C2D-56FD4327B942}.Debug.ActiveCfg = Debug|Win32
+		{81F22EF9-A1B8-46CB-9C2D-56FD4327B942}.Debug.Build.0 = Debug|Win32
+		{81F22EF9-A1B8-46CB-9C2D-56FD4327B942}.Release.ActiveCfg = Release|Win32
+		{81F22EF9-A1B8-46CB-9C2D-56FD4327B942}.Release.Build.0 = Release|Win32
+		{9A751791-929F-496A-8DE7-B61020619BFA}.Debug.ActiveCfg = Debug|Win32
+		{9A751791-929F-496A-8DE7-B61020619BFA}.Debug.Build.0 = Debug|Win32
+		{9A751791-929F-496A-8DE7-B61020619BFA}.Release.ActiveCfg = Release|Win32
+		{9A751791-929F-496A-8DE7-B61020619BFA}.Release.Build.0 = Release|Win32
+		{465BDB84-92B5-4C60-AF26-8BD1A61A089E}.Debug.ActiveCfg = Debug|Win32
+		{465BDB84-92B5-4C60-AF26-8BD1A61A089E}.Debug.Build.0 = Debug|Win32
+		{465BDB84-92B5-4C60-AF26-8BD1A61A089E}.Release.ActiveCfg = Release|Win32
+		{465BDB84-92B5-4C60-AF26-8BD1A61A089E}.Release.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal

+ 5 - 0
tools/regression/index.htm

@@ -32,6 +32,11 @@ used to generate the actual status reports.</p>
         files.</li>
     <li><a href="build/Jamfile.v2">Jamfile.v2</a> - Builds
         process_jam_log and compiler_status executables.</li>
+    <li><a href="library_status.html">Library Status</a> - Runs test
+        programs for one or all boost libraries on
+        your local installation and generates complete tables
+        to show which combinations of libraries, compilers,
+        compiler settings pass and fail at your local installation.</li>
 </ul>
 
 <hr>

+ 980 - 0
tools/regression/library_status.cpp

@@ -0,0 +1,980 @@
+//  Generate Compiler Status HTML from jam regression test output  -----------//
+
+//  Copyright Beman Dawes 2002.  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)
+
+//  See http://www.boost.org/tools/regression/ for documentation.
+
+//Note: This version of the original program builds a large table
+//which includes all build variations such as build/release, static/dynamic, etc.
+
+
+/*******************************************************************************
+
+This program was designed to work unchanged on all platforms and
+configurations.  All output which is platform or configuration dependent
+is obtained from external sources such as the .xml file from
+process_jam_log execution, the tools/build/xxx-tools.jam files, or the
+output of the config_info tests.
+
+Please avoid adding platform or configuration dependencies during
+program maintenance.
+
+*******************************************************************************/
+
+#include "boost/filesystem/operations.hpp"
+#include "boost/filesystem/fstream.hpp"
+
+namespace fs = boost::filesystem;
+
+#include "detail/tiny_xml.hpp"
+namespace xml = boost::tiny_xml;
+
+#include "boost/iterator/transform_iterator.hpp"
+
+#include <cstdlib>  // for abort, exit
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <ctime>
+#include <stdexcept>
+#include <cassert>
+
+using std::string;
+
+const string pass_msg( "Pass" );
+const string warn_msg( "<i>Warn</i>" );
+const string fail_msg( "<font color=\"#FF0000\"><i>Fail</i></font>" );
+const string note_msg( "<sup>*</sup>" );
+const string missing_residue_msg( "<i>Missing</i>" );
+
+const std::size_t max_compile_msg_size = 10000;
+
+namespace
+{
+    fs::path boost_root;  // boost-root complete path
+    fs::path locate_root; // locate-root (AKA ALL_LOCATE_TARGET) complete path
+    bool ignore_pass = false;
+    bool no_warn = false;
+    bool no_links = false;
+
+    fs::directory_iterator end_itr;
+
+    // transform pathname to something html can accept
+    struct char_xlate {
+        typedef char result_type;
+        result_type operator()(char c) const{
+            if(c == '/')
+                return '-';
+            return c;
+        }
+    };
+    typedef boost::transform_iterator<char_xlate, std::string::const_iterator> html_from_path; 
+
+    template<class I1, class I2>
+    std::ostream & operator<<(
+    std::ostream &os, 
+    std::pair<I1, I2> p
+    ){
+        while(p.first != p.second)
+            os << *p.first++;
+        return os;
+    }
+
+    struct col_node {
+        int rows, cols;
+        bool is_leaf_directory;
+        std::string m_name;
+        std::set<col_node> m_subcolumns;
+        bool operator<(const col_node &cn) const;
+        col_node(const std::string &s) :
+        m_name(s),
+            is_leaf_directory(false)
+        {}
+        col_node(){};
+        std::pair<int, int> get_spans();
+        typedef std::set<col_node>::iterator iterator;
+        typedef std::set<col_node>::const_iterator const_iterator;
+    };
+
+    bool col_node::operator<(const col_node &cn) const {
+        return m_name < cn.m_name;
+    }
+
+    std::pair<int, int> col_node::get_spans(){
+        rows = 1;
+        cols = 0;
+        if(is_leaf_directory)
+            cols = 1;
+        std::set<col_node>::iterator itr;
+        for(itr = m_subcolumns.begin(); itr != m_subcolumns.end(); ++itr){
+            std::pair<int, int> spans;
+            spans = itr->get_spans();
+            rows = std::max(rows, spans.first);
+            cols += spans.second;
+        }
+        return std::make_pair(rows + 1, cols);
+    }
+
+    void build_node_tree(const fs::path & dir_root, col_node & node){
+        bool is_leaf_directory = true;
+        fs::directory_iterator itr(dir_root);
+        while(itr != end_itr){
+            if(fs::is_directory(*itr)){
+                std::pair<col_node::iterator, bool> result 
+                    = node.m_subcolumns.insert(col_node(itr->leaf()));
+                build_node_tree(*itr, *(result.first));
+                is_leaf_directory = false;
+            }
+            ++itr;
+        }
+        node.is_leaf_directory = is_leaf_directory;
+    }
+
+    fs::ofstream report;
+    fs::ofstream links_file;
+    string links_name;
+
+    fs::path notes_path;
+    string notes_html;
+
+    fs::path notes_map_path;
+    typedef std::multimap< string, string > notes_map; // key is test_name-toolset,
+    // value is note bookmark
+    notes_map notes;
+
+    string specific_compiler; // if running on one toolset only
+
+    const string empty_string;
+
+    //  build notes_bookmarks from notes HTML  -----------------------------------//
+
+    void build_notes_bookmarks()
+    {
+        if ( notes_map_path.empty() ) return;
+        fs::ifstream notes_map_file( notes_map_path );
+        if ( !notes_map_file )
+        {
+            std::cerr << "Could not open --notes-map input file: " << notes_map_path.string() << std::endl;
+            std::exit( 1 );
+        }
+        string line;
+        while( std::getline( notes_map_file, line ) )
+        {
+            string::size_type pos = 0;
+            if ( (pos = line.find( ',', pos )) == string::npos ) continue;
+            string key(line.substr( 0, pos ) );
+            string bookmark( line.substr( pos+1 ) );
+
+            //      std::cout << "inserting \"" << key << "\",\"" << bookmark << "\"\n";
+            notes.insert( notes_map::value_type( key, bookmark ) );
+        }
+    }
+
+    //  load_notes_html  ---------------------------------------------------------//
+
+    bool load_notes_html()
+    {
+        if ( notes_path.empty() ) return false;
+        fs::ifstream notes_file( notes_path );
+        if ( !notes_file )
+        {
+            std::cerr << "Could not open --notes input file: " << notes_path.string() << std::endl;
+            std::exit( 1 );
+        }
+        string line;
+        bool in_body( false );
+        while( std::getline( notes_file, line ) )
+        {
+            if ( in_body && line.find( "</body>" ) != string::npos ) in_body = false;
+            if ( in_body ) notes_html += line;
+            else if ( line.find( "<body>" ) ) in_body = true;
+        }
+        return true;
+    }
+
+    //  extract object library name from target directory string  ----------------//
+
+    string extract_object_library_name( const string & s )
+    {
+        string t( s );
+        string::size_type pos = t.find( "/build/" );
+        if ( pos != string::npos ) pos += 7;
+        else if ( (pos = t.find( "/test/" )) != string::npos ) pos += 6;
+        else return "";
+        return t.substr( pos, t.find( "/", pos ) - pos );
+    }
+
+    //  element_content  ---------------------------------------------------------//
+
+    const string & element_content(
+        const xml::element & root, const string & name )
+    {
+        static string empty_string;
+        xml::element_list::const_iterator itr;
+        for ( itr = root.elements.begin();
+            itr != root.elements.end() && (*itr)->name != name;
+            ++itr ) {}
+            return itr != root.elements.end() ? (*itr)->content : empty_string;
+    }
+
+    //  find_element  ------------------------------------------------------------//
+
+    const xml::element & find_element(
+        const xml::element & root, const string & name )
+    {
+        const xml::element empty_element;
+        xml::element_list::const_iterator itr;
+        for ( itr = root.elements.begin();
+            itr != root.elements.end() && (*itr)->name != name;
+            ++itr ) {}
+            return itr != root.elements.end() ? *((*itr).get()) : empty_element;
+    }
+
+    //  attribute_value  ----------------------------------------------------------//
+
+    const string & attribute_value( 
+        const xml::element & element,
+        const string & attribute_name 
+    ){
+        xml::attribute_list::const_iterator atr;
+        for(
+            atr = element.attributes.begin();
+            atr != element.attributes.end();
+            ++atr
+        ){
+            if(atr->name == attribute_name)
+                return atr->value;
+        }
+        const static string empty_string;
+        return empty_string;
+    }
+
+    //  generate_report  ---------------------------------------------------------//
+
+    // return 0 if nothing generated, 1 otherwise, except 2 if compiler msgs
+    int generate_report( 
+        const xml::element & db,
+        const std::string source_library_name,
+        const string & test_type,
+        const fs::path & target_dir,
+        bool pass,
+        bool always_show_run_output 
+        )
+    {
+        // compile msgs sometimes modified, so make a local copy
+        string compile( ((pass && no_warn)
+            ? empty_string :  element_content( db, "compile" )) );
+
+        const string & link( pass ? empty_string : element_content( db, "link" ) );
+        const string & run( (pass && !always_show_run_output)
+            ? empty_string : element_content( db, "run" ) );
+        string lib( (pass ? empty_string : element_content( db, "lib" )) );
+
+        // some compilers output the filename even if there are no errors or
+        // warnings; detect this if one line of output and it contains no space.
+        string::size_type pos = compile.find( '\n', 1 );
+        if ( pos != string::npos && compile.size()-pos <= 2
+            && compile.find( ' ' ) == string::npos ) compile.clear();
+
+        if ( lib.empty() 
+            && (
+                compile.empty() || test_type == "compile_fail"
+            ) 
+            && link.empty() 
+            && run.empty()
+        ) 
+            return 0; 
+
+        int result = 1; // some kind of msg for sure
+
+        // limit compile message length
+        if ( compile.size() > max_compile_msg_size )
+        {
+            compile.erase( max_compile_msg_size );
+            compile += "...\n   (remainder deleted because of excessive size)\n";
+        }
+
+        links_file << "<h2><a name=\"";
+        links_file << make_pair(
+            html_from_path(target_dir.string().begin()), 
+            html_from_path(target_dir.string().end())
+            )
+            << "\">"
+            << make_pair(
+            html_from_path(target_dir.string().begin()), 
+            html_from_path(target_dir.string().end())
+            )
+            ;
+        links_file << "</a></h2>\n";;
+
+        if ( !compile.empty() )
+        {
+            ++result;
+            links_file << "<h3>Compiler output:</h3><pre>"
+                << compile << "</pre>\n";
+        }
+        if ( !link.empty() )
+            links_file << "<h3>Linker output:</h3><pre>" << link << "</pre>\n";
+        if ( !run.empty() )
+            links_file << "<h3>Run output:</h3><pre>" << run << "</pre>\n";
+
+        // for an object library failure, generate a reference to the object
+        // library failure message, and (once only) generate the object
+        // library failure message itself
+        static std::set< string > failed_lib_target_dirs; // only generate once
+        if ( !lib.empty() )
+        {
+            if ( lib[0] == '\n' ) lib.erase( 0, 1 );
+            string object_library_name( extract_object_library_name( lib ) );
+
+            // changing the target directory naming scheme breaks
+            // extract_object_library_name()
+            assert( !object_library_name.empty() );
+            if ( object_library_name.empty() )
+                std::cerr << "Failed to extract object library name from " << lib << "\n";
+
+            links_file << "<h3>Library build failure: </h3>\n"
+                "See <a href=\"#"
+                << source_library_name << "-"
+                << object_library_name << "-" 
+                << make_pair(
+                html_from_path(target_dir.string().begin()), 
+                html_from_path(target_dir.string().end())
+                )
+                << source_library_name << " - "
+                << object_library_name << " - " 
+                << make_pair(
+                html_from_path(target_dir.string().begin()), 
+                html_from_path(target_dir.string().end())
+                )
+                << "</a>";
+            if ( failed_lib_target_dirs.find( lib ) == failed_lib_target_dirs.end() )
+            {
+                failed_lib_target_dirs.insert( lib );
+                fs::path pth( locate_root / lib / "test_log.xml" );
+                fs::ifstream file( pth );
+                if ( file )
+                {
+                    xml::element_ptr db = xml::parse( file, pth.string() );
+                    generate_report( 
+                        *db, 
+                        source_library_name, 
+                        test_type,
+                        target_dir,
+                        false,
+                        false
+                    );
+                }
+                else
+                {
+                    links_file << "<h2><a name=\""
+                        << object_library_name << "-" 
+                        << make_pair(
+                        html_from_path(target_dir.string().begin()), 
+                        html_from_path(target_dir.string().end())
+                        )
+                        << "\">"
+                        << object_library_name << " - " 
+                        << make_pair(
+                        html_from_path(target_dir.string().begin()), 
+                        html_from_path(target_dir.string().end())
+                        )
+                        << "</a></h2>\n"
+                        << "test_log.xml not found\n";
+                }
+            }
+        }
+        return result;
+    }
+
+    //  add_notes --------------------------------------------------------------//
+
+    void add_notes( const string & key, bool fail, string & sep, string & target )
+    {
+        notes_map::const_iterator itr = notes.lower_bound( key );
+        if ( itr != notes.end() && itr->first == key )
+        {
+            for ( ; itr != notes.end() && itr->first == key; ++itr )
+            {
+                string note_desc( itr->second[0] == '-'
+                    ? itr->second.substr( 1 ) : itr->second );
+                if ( fail || itr->second[0] == '-' )
+                {
+                    target += sep;
+                    sep = ",";
+                    target += "<a href=\"";
+                    target += "#";
+                    target += note_desc;
+                    target += "\">";
+                    target += note_desc;
+                    target += "</a>";
+                }
+            }
+        }
+    }
+
+    //  do_cell  ---------------------------------------------------------------//
+    bool do_cell(
+        const fs::path & target_dir,
+        const string & lib_name,
+        string & target,
+        bool profile
+    ){
+        // return true if any results except pass_msg
+        bool pass = false;
+
+        fs::path xml_file_path( target_dir / "test_log.xml" );
+        if ( !fs::exists( xml_file_path ) )
+        {
+            // suppress message because there are too many of them.
+            // "missing" is a legitmate result as its not a requirement
+            // that every test be run in every figuration.
+            //std::cerr << "Missing jam_log.xml in target:\n "
+            //    << target_dir.string() << "\n";
+            target += "<td align=\"right\">" + missing_residue_msg + "</td>";
+            return true;
+        }
+
+        int anything_generated = 0;
+        bool note = false;
+
+        fs::ifstream file( xml_file_path );
+        if ( !file ) // could not open jam_log.xml
+        {
+            std::cerr << "Can't open jam_log.xml in target:\n "
+                << target_dir.string() << "\n";
+            target += "<td>" + missing_residue_msg + "</td>";
+            return false;
+        }
+
+        string test_type( "unknown" );
+        bool always_show_run_output( false );
+
+        xml::element_ptr dbp = xml::parse( file, xml_file_path.string() );
+        const xml::element & db( *dbp );
+        test_type = attribute_value( db, "test-type" );
+        always_show_run_output
+            = attribute_value( db, "show-run-output" ) == "true";
+
+        std::string test_type_base( test_type );
+        if ( test_type_base.size() > 5 )
+        {
+            const string::size_type trailer = test_type_base.size() - 5;
+            if ( test_type_base.substr( trailer ) == "_fail" )
+            {
+                test_type_base.erase( trailer );
+            }
+        }
+        if ( test_type_base.size() > 4 )
+        {
+            const string::size_type trailer = test_type_base.size() - 4;
+            if ( test_type_base.substr( trailer ) == "_pyd" )
+            {
+                test_type_base.erase( trailer );
+            }
+        }
+        const xml::element & test_type_element( find_element( db, test_type_base ) );
+
+        pass = !test_type_element.name.empty()
+            && attribute_value( test_type_element, "result" ) != "fail";
+
+        if (!no_links){
+            if(!test_type_element.name.empty())
+                note = attribute_value( test_type_element, "result" ) == "note";
+            anything_generated = 
+                generate_report(
+                db, 
+                lib_name, 
+                test_type,
+                target_dir,
+                pass,
+                always_show_run_output || note 
+            );
+        }
+
+        // generate the status table cell pass/warn/fail HTML
+        target += "<td align=\"right\">";
+        if ( anything_generated != 0 )
+        {
+            target += "<a href=\"";
+            target += links_name;
+            target += "#";
+            std::copy(
+                html_from_path(target_dir.string().begin()), 
+                html_from_path(target_dir.string().end()),
+                std::back_inserter(target)
+                );
+            target += "\">";
+            target += pass
+                ? (anything_generated < 2 ? pass_msg : warn_msg)
+                : fail_msg;
+            target += "</a>";
+            if ( pass && note ) target += note_msg;
+        }
+        else  target += pass ? pass_msg : fail_msg;
+
+        // if profiling
+        if(profile && pass){
+            // add link to profile
+            target += " <a href=\"";
+            target += (target_dir / "profile.txt").string();
+            target += "\"><i>Profile</i></a>";
+        }
+        
+        // if notes, generate the superscript HTML
+//        if ( !notes.empty() ) 
+//            target += get_notes( toolset, lib_name, test_name, !pass );
+
+        target += "</td>";
+        return (anything_generated != 0) || !pass;
+    }
+
+    bool visit_node_tree(
+        const col_node & node,
+        fs::path dir_root,
+        const string & lib_name,
+        string & target,
+        bool profile
+    ){
+        bool retval = false;
+        if(node.is_leaf_directory){
+            retval = do_cell(
+                dir_root,
+                lib_name,
+                target,
+                profile
+            );
+        }
+
+        col_node::const_iterator col_itr;
+        for(
+            col_itr = node.m_subcolumns.begin(); 
+            col_itr != node.m_subcolumns.end();
+            ++col_itr
+        ){
+            fs::path subdir = dir_root / col_itr->m_name;
+            retval |= visit_node_tree(
+                *col_itr, 
+                subdir,
+                lib_name,
+                target,
+                col_itr->m_name == "profile"
+            );
+        }
+        return retval;
+    }
+
+    // emit results for each test
+    void do_row(
+        col_node test_node,
+        const fs::path & test_dir,
+        const string & lib_name,
+        const string & test_name,
+        string & target 
+    ){
+        string::size_type row_start_pos = target.size();
+
+        target += "<tr>";
+
+        target += "<td>";
+        //target += "<a href=\"" + url_prefix_dir_view + "/libs/" + lib_name + "\">";
+        target += test_name;
+        target += "</a>";
+        target += "</td>";
+
+//        target += "<td>" + test_type + "</td>";
+
+        bool no_warn_save = no_warn;
+
+//        if ( test_type.find( "fail" ) != string::npos ) no_warn = true;
+
+        // emit cells on this row
+        bool anything_to_report = visit_node_tree(
+            test_node, 
+            test_dir,
+            lib_name,
+            target,
+            false
+        );
+
+        target += "</tr>";
+
+        if ( ignore_pass 
+        && ! anything_to_report ) 
+            target.erase( row_start_pos );
+
+        no_warn = no_warn_save;
+    }
+
+    //  do_table_body  -----------------------------------------------------------//
+
+    void do_table_body(
+        col_node root_node, 
+        const string & lib_name,
+        const fs::path & test_lib_dir 
+    ){
+        // rows are held in a vector so they can be sorted, if desired.
+        std::vector<string> results;
+
+        for ( fs::directory_iterator itr( test_lib_dir ); itr != end_itr; ++itr )
+        {
+            if(! fs::is_directory(*itr))
+                continue;
+            
+            string test_name = itr->leaf();
+            // strip off the ".test" is there is one
+            string::size_type s = test_name.find( ".test" );
+            if(string::npos != s)
+                test_name.resize(s);
+
+            results.push_back( std::string() ); 
+            do_row(
+                root_node, //*test_node_itr++,
+                *itr, // test dir
+                lib_name,
+                test_name,
+                results[results.size()-1] 
+            );
+        }
+
+        std::sort( results.begin(), results.end() );
+
+        for ( 
+            std::vector<string>::iterator v(results.begin());
+            v != results.end(); 
+            ++v 
+        ){ 
+            report << *v << "\n"; 
+        }
+    }
+
+    //  column header-----------------------------------------------------------//
+    int header_depth(const col_node & root){
+        std::set<col_node>::const_iterator itr;
+        int max_depth = 1;
+        for(itr = root.m_subcolumns.begin(); itr != root.m_subcolumns.end(); ++itr){
+            max_depth = std::max(max_depth, itr->rows);
+        }
+        return max_depth;
+    }
+
+    void header_cell(int rows, int cols, const std::string & name){
+        // add row cells
+        report << "<td align=\"center\" " ;
+        if(1 < cols)
+            report << "colspan=\"" << cols << "\" " ;
+        if(1 < rows)
+            // span rows to the end the header
+            report << "rowspan=\"" << rows << "\" " ;
+        report << ">" ;
+        report << name;
+        report << "</td>\n";
+    }
+
+    void emit_column_headers(
+        const col_node & node, 
+        int display_row, 
+        int current_row,
+        int row_count
+    ){
+        if(current_row < display_row){
+            if(! node.m_subcolumns.empty()){
+                std::set<col_node>::const_iterator itr;
+                for(itr = node.m_subcolumns.begin(); itr != node.m_subcolumns.end(); ++itr){
+                    emit_column_headers(*itr, display_row, current_row + 1, row_count);
+                }
+            }
+            return;
+        }
+        if(node.is_leaf_directory && ! node.m_subcolumns.empty()){
+            header_cell(row_count - current_row, 1, std::string(""));
+        }
+        std::set<col_node>::const_iterator itr;
+        for(itr = node.m_subcolumns.begin(); itr != node.m_subcolumns.end(); ++itr){
+            if(1 == itr->rows)
+                header_cell(row_count - current_row, itr->cols, itr->m_name);
+            else
+                header_cell(1, itr->cols, itr->m_name);
+        }
+    }
+
+    fs::path find_lib_test_dir(){
+        // walk up from the path were we started until we find
+        // bin or bin.v2
+
+        fs::path::const_iterator leaf_itr = fs::initial_path().end();
+        fs::path test_lib_dir = fs::initial_path();
+        for(;;){
+            if(fs::is_directory( test_lib_dir / "bin.v2")){
+                test_lib_dir /= "bin.v2";
+                break;
+            }
+            if(fs::is_directory( test_lib_dir / "bin")){
+                // v1 includes the word boost
+                test_lib_dir /= "bin";
+                test_lib_dir /= "boost";
+                break;
+            }
+            if(test_lib_dir.empty())
+                throw std::string("binary path not found");
+            if(*leaf_itr != "libs")
+                --leaf_itr;
+            test_lib_dir.remove_leaf();
+        }
+
+        if(leaf_itr == fs::initial_path().end())
+            throw std::string("must be run from within a library directory");
+
+        while(leaf_itr != fs::initial_path().end()){
+            test_lib_dir /= *leaf_itr++;    // append "libs"
+        }
+        return test_lib_dir;
+    }
+
+    // note : uncomment the #if/#endif and what this compile !!!
+    string find_lib_name(fs::path lib_test_dir){
+        unsigned int count;
+        fs::path::iterator e_itr = lib_test_dir.end();
+        for(count =  0;; ++count){
+            if(*--e_itr == "libs")
+                break;
+            if(lib_test_dir.empty())
+                throw std::string("must be run from within a library directory");
+        }
+        string library_name;
+        for(;;){
+            library_name.append(*++e_itr);
+            if(1 == --count)
+                break;
+            library_name.append("/");
+        }
+        return library_name;
+    }
+
+    fs::path find_boost_root(){
+        fs::path boost_root = fs::initial_path();
+        for(;;){
+            if(fs::is_directory( boost_root / "boost")){
+                break;
+            }
+            if(boost_root.empty())
+                throw std::string("boost root not found");
+            boost_root.remove_leaf();
+        }
+
+        return boost_root;
+    }
+
+    //  do_table  ----------------------------------------------------------------//
+    void do_table(const string & lib_name)
+    {
+        col_node root_node;
+
+        fs::path lib_test_dir = find_lib_test_dir();
+
+        for ( fs::directory_iterator itr(lib_test_dir); itr != end_itr; ++itr )
+        {
+            if(! fs::is_directory(*itr))
+                continue;
+            build_node_tree(*itr, root_node);
+        }
+
+        // visit directory nodes and record nodetree
+        report << "<table border=\"1\" cellspacing=\"0\" cellpadding=\"5\">\n";
+
+        // emit
+        root_node.get_spans();
+        int row_count = header_depth(root_node);
+        report << "<tr>\n";
+        report << "<td rowspan=\"" << row_count << "\">Test Name</td>\n";
+
+        // emit column headers
+        int row_index = 0;
+        for(;;){
+            emit_column_headers(root_node, row_index, 0, row_count);
+            report << "</tr>" ;
+            if(++row_index == row_count)
+                break;
+            report << "<tr>\n";
+        }
+
+        // now the rest of the table body
+        do_table_body(root_node, lib_name, lib_test_dir);
+
+        report << "</table>\n";
+   }
+}// unnamed namespace
+
+//  main  --------------------------------------------------------------------//
+
+#define BOOST_NO_CPP_MAIN_SUCCESS_MESSAGE
+#include <boost/test/included/prg_exec_monitor.hpp>
+
+int cpp_main( int argc, char * argv[] ) // note name!
+{
+    fs::path comment_path;
+    while ( argc > 1 && *argv[1] == '-' )
+    {
+        if ( argc > 2 && std::strcmp( argv[1], "--compiler" ) == 0 )
+        { specific_compiler = argv[2]; --argc; ++argv; }
+        else if ( argc > 2 && std::strcmp( argv[1], "--locate-root" ) == 0 )
+        { locate_root = fs::path( argv[2], fs::native ); --argc; ++argv; }
+        else if ( argc > 2 && std::strcmp( argv[1], "--boost-root" ) == 0 )
+        { boost_root = fs::path( argv[2], fs::native ); --argc; ++argv; }
+        else if ( argc > 2 && std::strcmp( argv[1], "--comment" ) == 0 )
+        { comment_path = fs::path( argv[2], fs::native ); --argc; ++argv; }
+        else if ( argc > 2 && std::strcmp( argv[1], "--notes" ) == 0 )
+        { notes_path = fs::path( argv[2], fs::native ); --argc; ++argv; }
+        else if ( argc > 2 && std::strcmp( argv[1], "--notes-map" ) == 0 )
+        { notes_map_path = fs::path( argv[2], fs::native ); --argc; ++argv; }
+        else if ( std::strcmp( argv[1], "--ignore-pass" ) == 0 ) ignore_pass = true;
+        else if ( std::strcmp( argv[1], "--no-warn" ) == 0 ) no_warn = true;
+        else if ( std::strcmp( argv[1], "--v2" ) == 0 )
+        {--argc; ++argv ;} // skip
+        else if ( argc > 2 && std::strcmp( argv[1], "--jamfile" ) == 0)
+        {--argc; ++argv;} // skip
+        else { std::cerr << "Unknown option: " << argv[1] << "\n"; argc = 1; }
+        --argc;
+        ++argv;
+    }
+
+    if ( argc != 2 && argc != 3 )
+    {
+        std::cerr <<
+            "Usage: library_status [options...] status-file [links-file]\n"
+            "  boost-root is the path to the boost tree root directory.\n"
+            "  status-file and links-file are paths to the output files.\n"
+            "  options: --compiler name     Run for named compiler only\n"
+            "           --ignore-pass       Do not report tests which pass all compilers\n"
+            "           --no-warn           Warnings not reported if test passes\n"
+		    "           --boost-root path default derived from current path.\n"
+		    "           --locate-root path  Path to ALL_LOCATE_TARGET for bjam;\n"
+		    "                               default boost-root.\n"
+            "           --comment path      Path to file containing HTML\n"
+            "                               to be copied into status-file.\n"
+            "           --notes path        Path to file containing HTML\n"
+            "                               to be copied into status-file.\n"
+            "           --notes-map path    Path to file of toolset/test,n lines, where\n"
+            "                               n is number of note bookmark in --notes file.\n"
+            "Example: compiler_status --compiler gcc /boost-root cs.html cs-links.html\n"
+            "Note: Only the leaf of the links-file path and --notes file string are\n"
+            "used in status-file HTML links. Thus for browsing, status-file,\n"
+            "links-file, and --notes file must all be in the same directory.\n"
+            ;
+        return 1;
+    }
+
+	if(boost_root.empty())
+		boost_root = find_boost_root();
+	if ( locate_root.empty() ) 
+		locate_root = boost_root;
+
+    report.open( fs::path( argv[1], fs::native ) );
+    if ( !report )
+    {
+        std::cerr << "Could not open report output file: " << argv[2] << std::endl;
+        return 1;
+    }
+
+    if ( argc == 3 )
+    {
+        fs::path links_path( argv[2], fs::native );
+        links_name = links_path.leaf();
+        links_file.open( links_path );
+        if ( !links_file )
+        {
+            std::cerr << "Could not open links output file: " << argv[3] << std::endl;
+            return 1;
+        }
+    }
+    else no_links = true;
+
+    build_notes_bookmarks();
+
+    const string library_name = find_lib_name(fs::initial_path());
+
+    char run_date[128];
+    std::time_t tod;
+    std::time( &tod );
+    std::strftime( run_date, sizeof(run_date),
+        "%X UTC, %A %d %B %Y", std::gmtime( &tod ) );
+
+    report 
+        << "<html>\n"
+        << "<head>\n"
+        << "<title>Boost Library Status Automatic Test</title>\n"
+        << "</head>\n"
+        << "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
+        << "<table border=\"0\">\n"
+        << "<tr>\n"
+        << "<td><img border=\"0\" " 
+        << "src=\""
+        << boost_root / "boost.png"
+        << "\" width=\"277\" "
+        << "height=\"86\"></td>\n"
+        << "<td>\n"
+        << "<h1>Library Status: " + library_name + "</h1>\n"
+        << "<b>Run Date:</b> "
+        << run_date
+        << "\n"
+        ;
+
+    if ( !comment_path.empty() )
+    {
+        fs::ifstream comment_file( comment_path );
+        if ( !comment_file )
+        {
+            std::cerr << "Could not open \"--comment\" input file: " << comment_path.string() << std::endl;
+            return 1;
+        }
+        char c;
+        while ( comment_file.get( c ) ) { report.put( c ); }
+    }
+
+    report << "</td>\n</table>\n<br>\n";
+
+    if ( !no_links )
+    {
+        links_file
+            << "<html>\n"
+            << "<head>\n"
+            << "<title>Boost Library Status Error Log</title>\n"
+            << "</head>\n"
+            << "<body bgcolor=\"#ffffff\" text=\"#000000\">\n"
+            << "<table border=\"0\">\n"
+            << "<tr>\n"
+            << "<td><img border=\"0\" src=\""
+            << boost_root / "boost.png"
+            << "\" width=\"277\" "
+            << "height=\"86\"></td>\n"
+            << "<td>\n"
+            << "<h1>Library Status: " + library_name + "</h1>\n"
+            << "<b>Run Date:</b> "
+            << run_date
+            << "\n</td>\n</table>\n<br>\n"
+            ;
+    }
+
+    do_table(library_name);
+
+    if ( load_notes_html() ) report << notes_html << "\n";
+
+    report << "</body>\n"
+        "</html>\n"
+        ;
+
+    if ( !no_links )
+    {
+        links_file
+            << "</body>\n"
+            "</html>\n"
+            ;
+    }
+    return 0;
+}

+ 166 - 0
tools/regression/library_status.html

@@ -0,0 +1,166 @@
+<html>
+
+<head>
+<meta http-equiv="Content-Language" content="en-us">
+<meta http-equiv="Content-Type"
+content="text/html; charset=iso-8859-1">
+<title>Libary Status</title>
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<table border="0">
+<tr>
+<td><img border="0" src="../../boost.png" width="277" height="86" alt="boost.png (6897 bytes)"></td>
+<td><h1>Generating Library Status Tables</h1></td>
+</tr>
+</table>
+
+<h3>Purpose</h3>
+Any time one considers using a library as large and complex
+as the Boost libraries, he must have a way of validating
+the the library functions in his environment.  This should
+be done when the library is installed and anytime questions
+are raised regarding its applicabililty and/or its usage.
+<p>
+The procedures described here permit a user to run any
+combination of tests on any or all libraries and generate
+a set of convenient tables which show which libraries
+pass which tests under what conditions.
+<h3>Preliminaries</h3>
+Generating these tables requires a couple of utility programs:
+<code>process_jam_log</code> and <code>library_status</code>. 
+These can be built by moving to the directory <code>tools/regression/build</code>
+and invoking bjam. If all goes well these utility programs
+will be found in the directory <code>dist/bin</code>.  From
+there they should be moved to a place in the current
+path.
+<p>
+<h3>Running Tests for One Library</h3>
+
+<ol>
+    <li>Start from your command line environment.
+    <li>set the current directory to:../libs/&lt;library name&gt;/test
+    <li>Invoke one of the following:
+    <ul>
+        <li><code>../../../tools/regression/library_test (*nix)</code>.
+        <li><code>..\..\..\tools\regression\library_test (windows)</code>.
+    </ul>
+    <li>This will display short help message describing the how to set
+    the command line arguments for the compilers and variants you want to
+    appear in the final table.
+    <li>Setting these arguments requires rudimentary knowledge of bjam
+    usage. Hopefully, if you've arrived at this page you've gained the
+    required knowledge during the installation and library build process.
+    <li>Rerun the abve command with the argument set accordingly.
+    <li>When the command terminates, there should be a file named 
+    "library_status.html" in the current directory.
+    <li>Display this file with any web browser.
+</ol>
+There should appear a table similar to the following for the regex
+library.
+<p>
+<table border="1" cellspacing="0" cellpadding="5">
+<tr>
+<td rowspan="4">Test Name</td>
+<td align="center" colspan="4" >msvc-7.1</td>
+</tr><tr>
+<td align="center" colspan="2" >debug</td>
+<td align="center" colspan="2" >release</td>
+</tr><tr>
+<td align="center" >link-static</td>
+<td align="center" rowspan="2" >threading-multi</td>
+<td align="center" >link-static</td>
+<td align="center" rowspan="2" >threading-multi</td>
+</tr><tr>
+<td align="center" >threading-multi</td>
+<td align="center" >threading-multi</td>
+</tr><tr><td>bad_expression_test</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-bad_expression_test.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-bad_expression_test.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>captures</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-captures-msvc-7.1-debug-threading-multi"><font color="#FF0000"><i>Fail</i></font></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-captures-msvc-7.1-release-threading-multi"><font color="#FF0000"><i>Fail</i></font></a></td></tr>
+<tr><td>captures_test</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-captures_test.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-captures_test.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>concept_check</a></td><td align="right"><i>Missing</i></td><td align="right">Pass</td><td align="right"><i>Missing</i></td><td align="right">Pass</td></tr>
+<tr><td>icu_concept_check</a></td><td align="right"><i>Missing</i></td><td align="right">Pass</td><td align="right"><i>Missing</i></td><td align="right">Pass</td></tr>
+<tr><td>object_cache_test</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-object_cache_test.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-object_cache_test.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>posix_api_check</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-posix_api_check.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-posix_api_check.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>posix_api_check_cpp</a></td><td align="right"><i>Missing</i></td><td align="right">Pass</td><td align="right"><i>Missing</i></td><td align="right">Pass</td></tr>
+<tr><td>recursion_test</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-recursion_test.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-recursion_test.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>regex_config_info</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_config_info.test-msvc-7.1-debug-threading-multi">Pass</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_config_info.test-msvc-7.1-release-threading-multi">Pass</a></td></tr>
+<tr><td>regex_dll_config_info</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_dll_config_info.test-msvc-7.1-debug-threading-multi">Pass</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_dll_config_info.test-msvc-7.1-release-threading-multi">Pass</a></td></tr>
+<tr><td>regex_regress</a></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_regress.test-msvc-7.1-debug-link-static-threading-multi">Pass</a><sup>*</sup></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_regress.test-msvc-7.1-release-link-static-threading-multi">Pass</a><sup>*</sup></td><td align="right"><i>Missing</i></td></tr>
+<tr><td>regex_regress_dll</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_regress_dll.test-msvc-7.1-debug-threading-multi">Pass</a><sup>*</sup></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-regex_regress_dll.test-msvc-7.1-release-threading-multi">Pass</a><sup>*</sup></td></tr>
+<tr><td>regex_regress_threaded</a></td><td align="right"><i>Missing</i></td><td align="right">Pass</td><td align="right"><i>Missing</i></td><td align="right">Pass</td></tr>
+<tr><td>static_mutex_test</a></td><td align="right"><i>Missing</i></td><td align="right">Pass</td><td align="right"><i>Missing</i></td><td align="right">Pass</td></tr>
+<tr><td>test_collate_info</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-test_collate_info.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-test_collate_info.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>unicode_iterator_test</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-unicode_iterator_test.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-unicode_iterator_test.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>wide_posix_api_check_c</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-wide_posix_api_check_c.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-wide_posix_api_check_c.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+<tr><td>wide_posix_api_check_cpp</a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-wide_posix_api_check_cpp.test-msvc-7.1-debug-threading-multi"><i>Warn</i></a></td><td align="right"><i>Missing</i></td><td align="right"><a href="links.html#C:-Boost134-bin.v2-libs-regex-test-wide_posix_api_check_cpp.test-msvc-7.1-release-threading-multi"><i>Warn</i></a></td></tr>
+</table>
+<p>
+This table was generated by invoking the following command line:
+<p>
+<code>
+../../../tools/regression/library_test --toolset=msvc-7.1 variant=debug,release
+</code>
+<p>
+from within the .../libs/regex/test directory.
+<p>
+This table shows the regex test results for both debug and release
+versions of the library.  Also it displays the fact that one of the
+tests is run specifically with the static linking/multi-threading
+versions of the runtime libraries.  The cells marked "Missing" correspond
+to tests that were not run for some reason or another.  This is usually
+because the corresponding <code>Jamfile.v2</code> excludes this test
+for the given combination of compiler and build attributes. In this
+example, all tests were run with the same compiler.  If additional
+compilers were used, they would appear as more columns in the table.
+<p>
+The table above is just an illustration so the links don't actually
+point to anything.  In the table you generated, the links will
+display a page describing any errors, warnings or other available 
+information about the tests.  If the test passes, usually, there
+is no additional information and hence no link.
+<p>
+The tables are cumulative. That is, if you run one set of tests
+now and tests with different attributes later, the table will
+contain all the results to date.  The test results are stored
+in <code>../bin.v2/libs/test/&lt;library%gt;/...</code>.
+To reinitialize the test results to empty, delete the corresponding
+files in this directory.
+<p>
+The procedure above assumes that the table are generated within
+the directory <code>../libs/&lt;library&gt;/test</code>.  This is the
+most common case since this directory contains the
+<code>Jamfile.v2</code> as well as the source code that is
+used by official boost testers.  However, this is just a convention.
+The table can be generated for other directories within the
+libary.  One possiblity would be to generate the table for
+all the examples in <code>../libs/%lt;library%gt;/example</code>. Or
+one might have a special directory of performance tests which
+take a long time to run and hence are not suitable for running
+by official boost testers.  Just remember that library
+status table is generated in the directory from which the
+<code>library_test</code> command is invoked.
+<p>
+<h3>Running Tests for All Libraries</h3>
+For those with *nix or cygwin command line shells, there is shell
+script that can be run from the boost root directory:
+<p>
+<code> tools/regression/library_test_all</code>
+<p>
+The command line arguments are the same as for running the test
+for one library.  This script creates all the html files in all
+the test directories as well as an html page in the <code>status</code>
+directory named <code>library_status_summary.html</code>.  This
+can be used to browse through all test results for all test in
+all libraries.
+<hr>
+
+<p>
+Copyright 2007 Robert Ramey. 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)
+<p>
+Revised <!--webbot bot="Timestamp" startspan s-type="EDITED"
+s-format="%d %B, %Y" -->14 August, 2007<!--webbot bot="Timestamp"
+i-checksum="38582" endspan --></p>
+</body>
+</html>

+ 15 - 0
tools/regression/library_test.bat

@@ -0,0 +1,15 @@
+@echo off
+if not "%1" == "" goto bjam
+    echo Usage: %0 "<bjam arguments>"
+    echo where typical bjam arguements are:
+    echo   --toolset=msvc-7.1,gcc
+    echo   variant=debug,release,profile
+    echo   link=static,shared
+    echo   threading=single,multi
+    echo   -sBOOST_ARCHIVE_LIST="<archive name>"
+    goto end
+:bjam
+    bjam --dump-tests %* >bjam.log 2>&1
+    process_jam_log --v2 <bjam.log
+    library_status library_status.html links.html
+:end

+ 14 - 0
tools/regression/library_test.sh

@@ -0,0 +1,14 @@
+if test $# -eq 0 
+then
+    echo "Usage: $0 <bjam arguments>"
+    echo "Typical bjam arguements are:"
+    echo "  --toolset=msvc-7.1,gcc"
+    echo "  variant=debug,release,profile"
+    echo "  link=static,shared"
+    echo "  threading=single,multi"
+    echo "  -sBOOST_ARCHIVE_LIST=<archive name>"
+else
+    bjam --dump-tests $@ >bjam.log 2>&1
+    process_jam_log --v2 <bjam.log
+    library_status library_status.html links.html
+fi

+ 85 - 0
tools/regression/library_test_all.sh

@@ -0,0 +1,85 @@
+if test $# -eq 0
+then
+    echo "Usage: $0 <bjam arguments>"
+    echo "Typical bjam arguments are:"
+    echo "  --toolset=msvc-7.1,gcc"
+    echo "  variant=debug,release,profile"
+    echo "  link=static,shared"
+    echo "  threading=single,multi"
+    echo
+    echo "note: make sure this script is run from boost root directory !!!"
+    exit 1
+fi
+
+if ! test -e libs
+then
+    echo No libs directory found. Run from boost root directory !!!
+    exit 1
+fi
+
+#html header
+cat <<end >status/library_status_contents.html
+<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<!--
+(C) Copyright 2007 Robert Ramey - http://www.rrsd.com . 
+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)
+-->
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<link rel="stylesheet" type="text/css" href="../boost.css">
+<title>Library Status Contents</title>
+<body>
+end
+
+cd >nul libs
+
+# runtests, create library pages, and body of summary page
+for lib_name in *
+do
+    if test -d $lib_name
+    then
+        cd >nul $lib_name
+
+        if test -e "test/Jamfile.v2"
+        then
+            cd >nul test
+            echo $lib_name
+            echo >>../../../status/library_status_contents.html "<a target=\"detail\" href=\"../libs/$lib_name/test/library_status.html\">$lib_name</a><br>"
+            ../../../tools/regression/library_test $@
+            cd >nul ..
+        fi
+
+        for sublib_name in *
+        do
+            if test -d $sublib_name
+            then
+                cd >nul $sublib_name
+                if test -e "test/Jamfile.v2"
+                then
+                    cd >nul test
+                    echo $lib_name/$sublib_name
+                    echo >>../../../../status/library_status_contents.html "<a target=\"detail\" href=\"../libs/$lib_name/$sublib_name/test/library_status.html\">$lib_name/$sublib_name</a><br>"
+                    ../../../../tools/regression/library_test $@
+                    cd >nul ..
+                fi
+                cd >nul ..
+            fi
+        done
+           
+        cd >nul ..
+    fi
+done
+
+
+cd >nul ..
+
+#html trailer
+cat <<end >>status/library_status_contents.html
+</body>
+</html>
+end
+
+

+ 36 - 40
tools/regression/process_jam_log.cpp

@@ -128,10 +128,15 @@ namespace
   {
     string temp( s );
     convert_path_separators( temp );
-    temp.erase( temp.find_last_of( "/" ) ); // remove leaf
+    string::size_type pos = temp.find_last_of( "/");
+    if(pos == string::npos)
+        temp = "./";
+    else{
+        temp.erase( pos ); // remove leaf
     temp = split( trim_left( temp ) ).back();
     if ( temp[0] == '.' ) temp.erase( 0, temp.find_first_not_of( "./" ) ); 
     else temp.erase( 0, locate_root.string().size()+1 );
+    }
     if ( echo )
         std::cout << "\ttarget_directory( \"" << s << "\") -> \"" << temp << "\"" << std::endl;
     return temp;
@@ -171,52 +176,43 @@ namespace
   // returns library name corresponding to that path.
   string test_path_to_library_name( string const& path )
   {
-    std::string result;
-    string::size_type start_pos( path.find( "libs/" ) );
-    if ( start_pos != string::npos )
-    {
-      // The path format is ...libs/functional/hash/test/something.test/....      
-      // So, the part between "libs" and "test/something.test" can be considered
+    // The path format is ...libs/.../something.test/....      
+    // So, the part between "libs" and "something.test" can be considered
       // as library name. But, for some libraries tests are located too deep,
       // say numeric/ublas/test/test1 directory, and some libraries have tests
-      // in several subdirectories (regex/example and regex/test). So, nested
-      // directory may belong to several libraries.
-
-      // To disambituate, it's possible to place a 'sublibs' file in
-      // a directory. It means that child directories are separate libraries.
-      // It's still possible to have tests in the directory that has 'sublibs'
-      // file.
-
-      std::string interesting;
-      start_pos += 5;
-      string::size_type end_pos( path.find( ".test/", start_pos ) );
-      end_pos = path.rfind('/', end_pos);
-      if (path.substr(end_pos - 5, 5) == "/test")
-        interesting = path.substr( start_pos, end_pos - 5 - start_pos );
-      else
-        interesting = path.substr( start_pos, end_pos - start_pos );
-
-      // Take slash separate elements until we have corresponding 'sublibs'.
-      end_pos = 0;
-      for(;;)
-      {
-        end_pos = interesting.find('/', end_pos);
-        if (end_pos == string::npos) {
-          result = interesting;
-          break;
+    // in several subdirectories (regex/example and regex/test). So, its
+    // not a "library name" as it may include subdirectories
+
+    string::size_type end_pos = path.find(".test/");
+    end_pos = path.rfind("/", end_pos);
+
+    string::size_type start_pos;
+    string::size_type pos = end_pos;
+    unsigned int i;
+    for(i = 0;; ++i){
+        start_pos = path.rfind("/", pos - 1);
+
+        if ( start_pos == string::npos )
+            return string(); // empty string
+
+        ++start_pos;
+
+        const std::string dir = path.substr(start_pos, pos - start_pos);
+        if(0 == i){
+           // if this directory is either "test" or "example"
+           // skip it in order to be compatible with testing.jam
+           if("test" == dir
+           || "example" == dir){
+                end_pos = start_pos - 1;
         }
-        result = interesting.substr(0, end_pos);
-
-        if ( fs::exists( ( boost_root / "libs" ) / result / "sublibs" ) )
-        {
-          end_pos = end_pos + 1;
         }
-        else
+        if("libs" == dir){
+            start_pos = pos + 1;
           break;
       }
+        pos = start_pos - 1;
     }
-
-    return result;
+    return path.substr(start_pos, end_pos - start_pos);
   }
 
   // Tries to find target name in the string 'msg', starting from 

粤ICP备19079148号