diff --git a/.clang-format b/.clang-format index 2b3c0d1550..6a4a060922 100644 --- a/.clang-format +++ b/.clang-format @@ -2,7 +2,7 @@ BasedOnStyle: WebKit IndentWidth: 4 TabWidth: 4 -UseTab: ForContinuationAndIndentation +UseTab: Never --- Language: Cpp AccessModifierOffset: 0 diff --git a/doc/src/history.adoc b/doc/src/history.adoc index 65671e552f..524a08058f 100644 --- a/doc/src/history.adoc +++ b/doc/src/history.adoc @@ -1,6 +1,35 @@ [[b2.history]] = History +== Version 5.1.0 + +This is mostly a bugfix release to account for issues impacting Boost Libraries. +There is one "big" change though. It can be rather difficult to find build +failures when running larger builds. To facilitate figuring out problems the +brief summary output at the end of a build is now less brief. It now includes +a *sorted* list of the targets that got skipped and failed. The output of those +lists mirrors the general skipped/failed items. Hence it's possible to search +for the same strings in the rest of the output quickly. + +* *New*: Add listing of failed and skipped targets to end of build summary to + make it easier to find what fails. + -- _René Ferdinand Rivera Morell_ +* *New*: Add `mpi.run-flags` to `mpi` toolset that allows for arbitrary flags + applied to running mpi targets. This allows, for example, adding + `--oversubscribe` flag to make it possible to run tests where the tasks are + more than the nodes available. + -- _René Ferdinand Rivera Morell_ +* Fix spurious errors when the header scanning tries to scan empty file names. + -- _René Ferdinand Rivera Morell_ +* Make C/C++/ObjC include directive scanning pattern more strict to avoid + trying to scan for empty file names. + -- _Andrey Semashev_ +* Fix mingw linker commands to always replace backslashes with forward slashes. + -- _Christian Seiler_ +* Fix QCC debug build flag. The QCC toolset was using an old, no longer + supported, debug symbols option. + -- _John McFarlane_ + == Version 5.0.1 * Fix compile errors for older versions of GCC and Clang toolset for the engine. diff --git a/src/build/project.jam b/src/build/project.jam index b1f9d01590..f95d4b55bc 100644 --- a/src/build/project.jam +++ b/src/build/project.jam @@ -248,6 +248,16 @@ rule search ( name ) { if [ path.is-rooted $(name) ] { + # Check for a regular B2 project at an exactly matched registered + # search path location. + for local dir in "$(.search-path.$(name))" + { + local jamfile = [ path.glob $(dir) : $(JAMROOT) $(JAMFILE) ] ; + if $(jamfile) + { + return $(dir) ; + } + } # Check for a regular B2 project relative to the search path and # project subdir. for local dir in "$(.search-path./)" diff --git a/src/build/version.jam b/src/build/version.jam index bf5a3282af..9b1d261fb0 100644 --- a/src/build/version.jam +++ b/src/build/version.jam @@ -9,8 +9,8 @@ import numbers ; # Mirror engine JAM_VERSION .major = 5 ; -.minor = 0 ; -.patch = 1 ; +.minor = 1 ; +.patch = 0 ; rule build ( ) diff --git a/src/engine/build.bat b/src/engine/build.bat index ef7f249753..37ff324d3b 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -188,6 +188,7 @@ set B2_SOURCES=%B2_SOURCES% mod_regex.cpp set B2_SOURCES=%B2_SOURCES% mod_sequence.cpp set B2_SOURCES=%B2_SOURCES% mod_set.cpp set B2_SOURCES=%B2_SOURCES% mod_string.cpp +set B2_SOURCES=%B2_SOURCES% mod_summary.cpp set B2_SOURCES=%B2_SOURCES% mod_sysinfo.cpp set B2_SOURCES=%B2_SOURCES% mod_version.cpp diff --git a/src/engine/build.sh b/src/engine/build.sh index e88efad963..912c9478d5 100755 --- a/src/engine/build.sh +++ b/src/engine/build.sh @@ -498,6 +498,7 @@ mod_regex.cpp \ mod_sequence.cpp \ mod_set.cpp \ mod_string.cpp \ +mod_summary.cpp \ mod_sysinfo.cpp \ mod_version.cpp \ " diff --git a/src/engine/headers.cpp b/src/engine/headers.cpp index 1b8b02c572..da2288dded 100644 --- a/src/engine/headers.cpp +++ b/src/engine/headers.cpp @@ -135,6 +135,12 @@ LIST * headers1( LIST * l, OBJECT * file, int rec, b2::regex::program re[] ) } #endif + if ( file->as_string().size == 0 ) + { + /* If the scanning was fed empty file names we just ignore them. */ + return l; + } + if ( !( f = fopen( object_str( file ), "r" ) ) ) { /* No source files will be generated when -n flag is passed */ diff --git a/src/engine/make1.cpp b/src/engine/make1.cpp index 0efd1f198c..c34aa14ee1 100644 --- a/src/engine/make1.cpp +++ b/src/engine/make1.cpp @@ -53,8 +53,11 @@ #include "output.h" #include "startup.h" +#include "mod_summary.h" + #include #include +#include #if !defined( NT ) || defined( __GNUC__ ) #include /* for unlink */ @@ -81,6 +84,10 @@ static struct int32_t made; } counts[ 1 ]; +static std::unique_ptr make_summary; +static const char * targets_failed = "targets failed"; +static const char * targets_skipped = "targets skipped"; + /* Target state. */ #define T_STATE_MAKE1A 0 /* make1a() should be called */ #define T_STATE_MAKE1B 1 /* make1b() should be called */ @@ -207,6 +214,9 @@ int32_t make1( LIST * targets ) int32_t status = 0; memset( (char *)counts, 0, sizeof( *counts ) ); + make_summary.reset(new b2::summary); + make_summary->group(targets_failed); + make_summary->group(targets_skipped); { LISTITER iter, end; @@ -247,15 +257,25 @@ int32_t make1( LIST * targets ) clear_state_freelist(); /* Talk about it. */ - if ( counts->failed ) - out_printf( "...failed updating %d target%s...\n", counts->failed, - counts->failed > 1 ? "s" : "" ); - if ( DEBUG_MAKE && counts->skipped ) - out_printf( "...skipped %d target%s...\n", counts->skipped, - counts->skipped > 1 ? "s" : "" ); if ( DEBUG_MAKE && counts->made ) - out_printf( "...updated %d target%s...\n", counts->made, + { + out_printf( "\n...updated %d target%s...\n", counts->made, counts->made > 1 ? "s" : "" ); + } + if ( DEBUG_MAKE && counts->skipped ) + { + out_printf( "\n...skipped %d target%s...\n", + make_summary->count(targets_skipped), + make_summary->count(targets_skipped) > 1 ? "s" : "" ); + make_summary->print(targets_skipped, " %s\n"); + } + if ( counts->failed ) + { + out_printf( "\n...failed updating %d target%s...\n", + make_summary->count(targets_failed), + make_summary->count(targets_failed) > 1 ? "s" : "" ); + make_summary->print(targets_failed, " %s\n"); + } /* If we were interrupted, exit now that all child processes have finished. */ @@ -425,6 +445,7 @@ static void make1b( state * const pState ) if ( ( t->status == EXEC_CMD_FAIL ) && t->actions ) { ++counts->skipped; + make_summary->message(targets_skipped, object_str( t->name )); if ( ( t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD ) { if ( !unlink( object_str( t->boundname ) ) ) @@ -432,8 +453,10 @@ static void make1b( state * const pState ) ); } else + { out_printf( "...skipped %s for lack of %s...\n", object_str( t->name ), failed_name ); + } } if ( t->status == EXEC_CMD_OK ) @@ -941,6 +964,13 @@ static void make1c_closure out_printf( "...failed %s ", object_str( cmd->rule->name ) ); list_print( lol_get( (LOL *)&cmd->args, 0 ) ); out_printf( "...\n" ); + std::string m = object_str( cmd->rule->name ); + for (auto i: b2::list_cref(lol_get( (LOL *)&cmd->args, 0 ))) + { + m += " "; + m += i->str(); + } + make_summary->message(targets_failed, m.c_str()); } /* On interrupt, set quit so _everything_ fails. Do the same for failed diff --git a/src/engine/mod_summary.cpp b/src/engine/mod_summary.cpp new file mode 100644 index 0000000000..1b23d04cd6 --- /dev/null +++ b/src/engine/mod_summary.cpp @@ -0,0 +1,40 @@ +/* +Copyright 2024 René Ferdinand Rivera Morell +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) +*/ + +#include "mod_summary.h" + +#include "output.h" + +namespace b2 { + +void summary::group(value_ref group) +{ + group_order.push_back(group); + groups.emplace(group, group_t(new group_t::element_type)); +} + +void summary::message(value_ref group, value_ref message) +{ + groups[group]->push_back(message); +} + +int summary::count(value_ref group) { return (int)(groups[group]->size()); } + +void summary::print(value_ref group, value_ref format) +{ + std::string format_str = format; + auto & g = groups[group]; + std::sort(g->begin(), g->end(), [](value_ref a, value_ref b) -> bool { + return std::strcmp(a->str(), b->str()) < 0; + }); + for (auto const & m : *g) + { + std::string m_str = m; + out_printf(format->str(), m_str.c_str()); + } +} + +} // namespace b2 diff --git a/src/engine/mod_summary.h b/src/engine/mod_summary.h new file mode 100644 index 0000000000..9b7f0ca619 --- /dev/null +++ b/src/engine/mod_summary.h @@ -0,0 +1,60 @@ +/* +Copyright 2024 René Ferdinand Rivera Morell +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt) +*/ + +#ifndef B2_MOD_SUMMARY_H +#define B2_MOD_SUMMARY_H + +#include "config.h" + +#include "bind.h" +#include "value.h" + +#include +#include +#include + +namespace b2 { + +class summary : public object +{ + public: + void group(value_ref group); + void message(value_ref group, value_ref message); + int count(value_ref group); + void print(value_ref group, value_ref format); + + private: + using group_t = std::unique_ptr>; + using groups_t = std::unordered_map; + + groups_t groups; + std::vector group_order; +}; + +struct summary_module : b2::bind::module_ +{ + const char * module_name = "summary"; + + template + void def(Binder & binder) + { + binder.def_class("summary", type_()) + .def(init_<>()) + .def(&summary::group, "group", "group" * _1) + .def(&summary::message, "message", "group" * _1, + "message" * _1n) + .def(&summary::count, "count", "group" * _1) + .def(&summary::print, "print", "group" * _1, + "format" * _1); + } +}; + +} // namespace b2 + +#endif diff --git a/src/engine/patchlevel.h b/src/engine/patchlevel.h index 9f0fdd4a13..56a68e8c5a 100644 --- a/src/engine/patchlevel.h +++ b/src/engine/patchlevel.h @@ -13,5 +13,5 @@ Distributed under the Boost Software License, Version 1.0. */ #define VERSION_MAJOR 5 -#define VERSION_MINOR 0 -#define VERSION_PATCH 1 +#define VERSION_MINOR 1 +#define VERSION_PATCH 0 diff --git a/src/tools/gcc.jam b/src/tools/gcc.jam index 0ab831be22..e5f8f53a46 100644 --- a/src/tools/gcc.jam +++ b/src/tools/gcc.jam @@ -1033,12 +1033,12 @@ rule link.dll ( targets * : sources * : properties * ) actions link bind LIBRARIES { - "$(CONFIG_COMMAND)" @($(<[1]:T).rsp:O=FC:<=@":>=":E=-L"$(LINKPATH)" -Wl,$(RPATH_OPTION)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<)" $(START-GROUP) "$(>:T)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)) + "$(CONFIG_COMMAND)" @($(<[1]:T).rsp:O=FC:<=@":>=":E=-L"$(LINKPATH)" -Wl,$(RPATH_OPTION)$(SPACE)-Wl,$(RPATH) -Wl,-rpath-link$(SPACE)-Wl,"$(RPATH_LINK)" -o "$(<:T)" $(START-GROUP) "$(>:T)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)) } actions link.dll bind LIBRARIES { - "$(CONFIG_COMMAND)" @($(<[1]:T).rsp:O=FC:<=@":>=":E=-L"$(LINKPATH)" -Wl,$(RPATH_OPTION)$(SPACE)-Wl,$(RPATH) -Wl,$(IMPLIB_OPTION:E=--out-implib),"$(<[2])" -o "$(<[1])" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,"$(SONAME_PREFIX:E=)$(<[1]:D=)" $(SHARED_OPTION:E=-shared) $(START-GROUP) "$(>:T)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)) + "$(CONFIG_COMMAND)" @($(<[1]:T).rsp:O=FC:<=@":>=":E=-L"$(LINKPATH)" -Wl,$(RPATH_OPTION)$(SPACE)-Wl,$(RPATH) -Wl,$(IMPLIB_OPTION:E=--out-implib),"$(<[2]:T)" -o "$(<[1]:T)" $(HAVE_SONAME)-Wl,$(SONAME_OPTION)$(SPACE)-Wl,"$(SONAME_PREFIX:E=)$(<[1]:D=)" $(SHARED_OPTION:E=-shared) $(START-GROUP) "$(>:T)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)) } ### diff --git a/src/tools/mpi.jam b/src/tools/mpi.jam index 3fe2ff9e10..305905581b 100644 --- a/src/tools/mpi.jam +++ b/src/tools/mpi.jam @@ -66,6 +66,8 @@ import toolset ; import type ; import path ; +feature mpi.run-flags : : free incidental ; + # Make this module a project project.initialize $(__name__) ; project mpi ; @@ -622,6 +624,8 @@ toolset.uses-features mpi.capture-output : ; +toolset.flags mpi.capture-output RUN_FLAGS ; + rule capture-output ( target : sources * : properties * ) { # Use the standard capture-output rule to run the tests @@ -636,7 +640,7 @@ rule capture-output ( target : sources * : properties * ) # We launch MPI processes using the "mpirun" equivalent specified by the user. LAUNCHER on $(target) = - [ on $(target) return $(.mpirun) $(.mpirun_flags) $(num_processes) ] ; + [ on $(target) return $(.mpirun) $(RUN_FLAGS) $(.mpirun_flags) $(num_processes) ] ; } # Creates a set of test cases to be run through the MPI launcher. The name, sources, diff --git a/src/tools/qcc.jam b/src/tools/qcc.jam index 96f927f4b8..5d915b6574 100644 --- a/src/tools/qcc.jam +++ b/src/tools/qcc.jam @@ -88,7 +88,7 @@ local rule check-target-platform } # Declare flags for compilation. -toolset.flags qcc.compile OPTIONS on : -gstabs+ ; +toolset.flags qcc.compile OPTIONS on : -g ; # Declare flags and action for compilation. toolset.flags qcc.compile OPTIONS off : -O0 ; @@ -215,7 +215,7 @@ generators.register [ new qcc-linking-generator qcc.link.dll : LIB OBJ # Declare flags for linking. # First, the common flags. -toolset.flags qcc.link OPTIONS on : -gstabs+ ; +toolset.flags qcc.link OPTIONS on : -g ; toolset.flags qcc.link OPTIONS on : -p ; toolset.flags qcc.link OPTIONS ; toolset.flags qcc.link LINKPATH ; diff --git a/src/tools/types/cpp.jam b/src/tools/types/cpp.jam index 27046aa097..c2ab01fdf7 100644 --- a/src/tools/types/cpp.jam +++ b/src/tools/types/cpp.jam @@ -30,7 +30,7 @@ class c-scanner : scanner rule pattern ( ) { - return "#[ \t]*include[ \t]*(<(.*)>|\"(.*)\")" ; + return "^[ \t]*#[ \t]*include[ \t]*(<(.+)>|\"(.+)\")" ; } rule process ( target : matches * : binding ) diff --git a/src/tools/types/objc.jam b/src/tools/types/objc.jam index 2762d97912..7d6ce0cbf3 100644 --- a/src/tools/types/objc.jam +++ b/src/tools/types/objc.jam @@ -14,7 +14,7 @@ class objc-scanner : c-scanner rule pattern ( ) { - return "#[ \t]*include|import[ ]*(<(.*)>|\"(.*)\")" ; + return "^[ \t]*#[ \t]*include|import[ ]*(<(.+)>|\"(.+)\")" ; } } diff --git a/test/core_actions_quietly.py b/test/core_actions_quietly.py index 6c0d75fe5e..87e1de6d84 100755 --- a/test/core_actions_quietly.py +++ b/test/core_actions_quietly.py @@ -49,12 +49,14 @@ [subtest_b] 0 [subtest_b] 1 [subtest_b] 2 + ...updated 2 targets... """) t.run_build_system(["-ffile.jam", "-d1"], stdout="""\ ...found 4 targets... ...updating 2 targets... + ...updated 2 targets... """) diff --git a/test/core_jamshell.py b/test/core_jamshell.py index 67292870b9..e1c0722802 100644 --- a/test/core_jamshell.py +++ b/test/core_jamshell.py @@ -49,7 +49,10 @@ t.expect_output_lines([ "...failed run test-raw-fail...", "0,1,2", + "", + "...updated 2 targets...", + "", "...failed updating 1 target...", - "...updated 2 targets..."]) + " run test-raw-fail"]) t.cleanup() diff --git a/test/core_multifile_actions.py b/test/core_multifile_actions.py index b6b78a5438..e322b2bac7 100755 --- a/test/core_multifile_actions.py +++ b/test/core_multifile_actions.py @@ -40,6 +40,7 @@ updating x1 x2 update x2 updating x2 x3 + ...updated 3 targets... """) @@ -59,6 +60,7 @@ updating x1 x2 update x2 updating x2 x3 + ...updated 3 targets... """) @@ -96,8 +98,11 @@ ...failed fail x1... update x2 updating x2 -...failed updating 2 targets... + ...updated 1 target... + +...failed updating 1 target... + fail x1 """) # Make sure that dependencies of targets that are @@ -124,6 +129,7 @@ updating x2 update x2 updating x2 x3 + ...updated 3 targets... """) @@ -147,6 +153,7 @@ ...updating 2 targets... update x1 updating x1 x2 + ...updated 2 targets... """) @@ -164,6 +171,7 @@ ...updating 1 target... update x1 updating x1 x1 + ...updated 1 target... """) @@ -194,6 +202,7 @@ updating x3 x4 : s4 update x4 updating x4 x3 : s5 + ...updated 4 targets... """) diff --git a/test/core_option_d2.py b/test/core_option_d2.py index 575923c7b6..62eecf3535 100755 --- a/test/core_option_d2.py +++ b/test/core_option_d2.py @@ -49,6 +49,7 @@ [subtest_b] 0 [subtest_b] 1 [subtest_b] 2 + ...updated 2 targets... """) diff --git a/test/core_option_n.py b/test/core_option_n.py index 3b90505a52..8e39e71ea0 100755 --- a/test/core_option_n.py +++ b/test/core_option_n.py @@ -44,6 +44,7 @@ echo [subtest_b] 1 echo [subtest_b] 2 + ...updated 2 targets... """) t.expect_nothing_more() diff --git a/test/core_parallel_actions.py b/test/core_parallel_actions.py index 6563c4fd97..a1a7ab6771 100755 --- a/test/core_parallel_actions.py +++ b/test/core_parallel_actions.py @@ -97,6 +97,7 @@ [.b] 0 [.b] 1 [.b] 2 + ...updated 8 targets... """) diff --git a/test/core_parallel_multifile_actions_1.py b/test/core_parallel_multifile_actions_1.py index 261bebe4c8..75ce4d65f3 100755 --- a/test/core_parallel_multifile_actions_1.py +++ b/test/core_parallel_multifile_actions_1.py @@ -72,6 +72,7 @@ 003 .use.2 u2.user 004 + ...updated 4 targets... """) diff --git a/test/core_parallel_multifile_actions_2.py b/test/core_parallel_multifile_actions_2.py index be66f731ef..419fbd314d 100755 --- a/test/core_parallel_multifile_actions_2.py +++ b/test/core_parallel_multifile_actions_2.py @@ -65,6 +65,7 @@ 001 - linked install installed_dll 002 - installed + ...updated 3 targets... """) diff --git a/test/core_update_now.py b/test/core_update_now.py index 5d7003010d..1d1f95da3f 100755 --- a/test/core_update_now.py +++ b/test/core_update_now.py @@ -31,6 +31,7 @@ def basic(): ...updating 1 target... do-print target1 updating target1 + ...updated 1 target... ...found 1 target... """) @@ -64,6 +65,7 @@ def ignore_minus_n(): echo updating target1 updating target1 + ...updated 1 target... ...found 1 target... """) @@ -106,13 +108,16 @@ def failed_target(): exit 1 ...failed fail target1... + ...failed updating 1 target... + fail target1 ...found 2 targets... ...updating 1 target... do-print target2 echo updating target2 + ...updated 1 target... """) @@ -181,12 +186,14 @@ def build_once(): echo updating target1 + ...updated 1 target... do-print target1 echo updating target1 updating target1 + ...updated 1 target... ...found 1 target... """) @@ -225,7 +232,9 @@ def return_status(): exit 1 ...failed fail target1... + ...failed updating 1 target... + fail target1 update1: update2: ...found 1 target... @@ -283,7 +292,10 @@ def save_restore(): exit 1 ...failed fail target2... + ...failed updating 2 targets... + fail target1 + fail target2 ...found 2 targets... ...updating 2 targets... fail target3 @@ -294,6 +306,7 @@ def save_restore(): exit 1 + ...updated 2 targets... ''') @@ -305,7 +318,9 @@ def save_restore(): exit 1 ...failed fail target1... + ...failed updating 1 target... + fail target1 ...found 2 targets... ...updating 2 targets... fail target3 @@ -313,7 +328,9 @@ def save_restore(): exit 1 ...failed fail target3... + ...failed updating 1 target... + fail target3 ''') t.run_build_system(['-n', '-sIGNORE_MINUS_Q=1', '-ffile.jam'], @@ -327,6 +344,7 @@ def save_restore(): exit 1 + ...updated 2 targets... ...found 2 targets... ...updating 2 targets... @@ -338,6 +356,7 @@ def save_restore(): exit 1 + ...updated 2 targets... ''') @@ -354,7 +373,10 @@ def save_restore(): exit 1 ...failed fail target2... + ...failed updating 2 targets... + fail target1 + fail target2 ...found 2 targets... ...updating 2 targets... fail target3 @@ -362,7 +384,9 @@ def save_restore(): exit 1 ...failed fail target3... + ...failed updating 1 target... + fail target3 ''') t.cleanup() diff --git a/test/timedata.py b/test/timedata.py index 3a4e25a787..08bd5c218d 100644 --- a/test/timedata.py +++ b/test/timedata.py @@ -82,6 +82,7 @@ def basic_jam_action_test(): make bar time foo bar +user: [0-9.]+ +system: +[0-9.]+ +clock: +[0-9.]+ * + \\.\\.\\.updated 2 targets\\.\\.\\.$ """