Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r84398 - in branches/release: . status tools tools/build tools/build/v2 tools/build/v2/build tools/build/v2/contrib tools/build/v2/doc tools/build/v2/doc/src tools/build/v2/engine tools/build/v2/engine/modules tools/build/v2/example/versioned tools/build/v2/kernel tools/build/v2/notes tools/build/v2/test tools/build/v2/test/core-language tools/build/v2/test/dependency-test tools/build/v2/test/generators-test tools/build/v2/test/module-actions tools/build/v2/test/unused tools/build/v2/tools tools/build/v2/tools/types tools/build/v2/util
From: steven_at_[hidden]
Date: 2013-05-21 00:14:47


Author: steven_watanabe
Date: 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
New Revision: 84398
URL: http://svn.boost.org/trac/boost/changeset/84398

Log:
Merge Boost.Build from the trunk.
Added:
   branches/release/tools/build/v2/build/config-cache.jam
      - copied unchanged from r83790, /trunk/tools/build/v2/build/config-cache.jam
   branches/release/tools/build/v2/engine/cwd.c
      - copied unchanged from r80373, /trunk/tools/build/v2/engine/cwd.c
   branches/release/tools/build/v2/engine/cwd.h
      - copied unchanged from r80373, /trunk/tools/build/v2/engine/cwd.h
   branches/release/tools/build/v2/engine/execcmd.c
      - copied, changed from r79057, /trunk/tools/build/v2/engine/execcmd.c
   branches/release/tools/build/v2/engine/pathnt.c
      - copied, changed from r80278, /trunk/tools/build/v2/engine/pathnt.c
   branches/release/tools/build/v2/engine/pathsys.c
      - copied unchanged from r80278, /trunk/tools/build/v2/engine/pathsys.c
   branches/release/tools/build/v2/engine/subst.h
      - copied unchanged from r79672, /trunk/tools/build/v2/engine/subst.h
   branches/release/tools/build/v2/test/MockToolset.py
      - copied, changed from r83773, /trunk/tools/build/v2/test/MockToolset.py
   branches/release/tools/build/v2/test/builtin_split_by_characters.py
      - copied, changed from r78669, /trunk/tools/build/v2/test/builtin_split_by_characters.py
   branches/release/tools/build/v2/test/collect_debug_info.py
      - copied, changed from r78918, /trunk/tools/build/v2/test/collect_debug_info.py
   branches/release/tools/build/v2/test/core_action_output.py
      - copied, changed from r79124, /trunk/tools/build/v2/test/core_action_output.py
   branches/release/tools/build/v2/test/core_nt_cmd_line.py
      - copied, changed from r79097, /trunk/tools/build/v2/test/core_nt_cmd_line.py
   branches/release/tools/build/v2/test/core_source_line_tracking.py
      - copied, changed from r79449, /trunk/tools/build/v2/test/core_source_line_tracking.py
   branches/release/tools/build/v2/test/core_variables_in_actions.py
      - copied, changed from r78670, /trunk/tools/build/v2/test/core_variables_in_actions.py
   branches/release/tools/build/v2/test/message.py
      - copied, changed from r80981, /trunk/tools/build/v2/test/message.py
   branches/release/tools/build/v2/test/project_id.py
      - copied, changed from r79939, /trunk/tools/build/v2/test/project_id.py
   branches/release/tools/build/v2/test/rescan_header.py
      - copied, changed from r78248, /trunk/tools/build/v2/test/rescan_header.py
   branches/release/tools/build/v2/test/scanner_causing_rebuilds.py
      - copied, changed from r79599, /trunk/tools/build/v2/test/scanner_causing_rebuilds.py
   branches/release/tools/build/v2/test/space_in_path.py
      - copied, changed from r78538, /trunk/tools/build/v2/test/space_in_path.py
   branches/release/tools/build/v2/test/static_and_shared_library.py
      - copied, changed from r78961, /trunk/tools/build/v2/test/static_and_shared_library.py
   branches/release/tools/build/v2/test/test_rc.py
      - copied, changed from r79148, /trunk/tools/build/v2/test/test_rc.py
   branches/release/tools/build/v2/test/zlib.py
      - copied, changed from r83773, /trunk/tools/build/v2/test/zlib.py
   branches/release/tools/build/v2/tools/jpeg.jam
      - copied unchanged from r83800, /trunk/tools/build/v2/tools/jpeg.jam
   branches/release/tools/build/v2/tools/png.jam
      - copied unchanged from r83800, /trunk/tools/build/v2/tools/png.jam
   branches/release/tools/build/v2/tools/tiff.jam
      - copied unchanged from r83800, /trunk/tools/build/v2/tools/tiff.jam
Removed:
   branches/release/tools/build/v2/build/modifiers.jam
   branches/release/tools/build/v2/engine/pwd.c
   branches/release/tools/build/v2/engine/pwd.h
   branches/release/tools/build/v2/example/versioned/
   branches/release/tools/build/v2/test/core_nt_line_length.py
   branches/release/tools/build/v2/test/dependency-test/
   branches/release/tools/build/v2/test/generators-test/
   branches/release/tools/build/v2/test/module-actions/
   branches/release/tools/build/v2/test/svn_tree.py
   branches/release/tools/build/v2/test/unused/
Properties modified:
   branches/release/ (props changed)
   branches/release/Jamroot (contents, props changed)
   branches/release/status/ (props changed)
   branches/release/status/explicit-failures-markup.xml (contents, props changed)
   branches/release/tools/ (props changed)
   branches/release/tools/build/ (props changed)
   branches/release/tools/build/v2/ (props changed)
Text files modified:
   branches/release/Jamroot | 2
   branches/release/status/explicit-failures-markup.xml | 18
   branches/release/tools/build/v2/bootstrap.sh | 16
   branches/release/tools/build/v2/build-system.jam | 311 ++--
   branches/release/tools/build/v2/build/ac.jam | 365 +++-
   branches/release/tools/build/v2/build/alias.jam | 3
   branches/release/tools/build/v2/build/build-request.jam | 14
   branches/release/tools/build/v2/build/build_request.py | 4
   branches/release/tools/build/v2/build/configure.jam | 186 +-
   branches/release/tools/build/v2/build/feature.jam | 57
   branches/release/tools/build/v2/build/generators.jam | 226 +-
   branches/release/tools/build/v2/build/project.jam | 595 +++++---
   branches/release/tools/build/v2/build/project.py | 236 +-
   branches/release/tools/build/v2/build/property-set.jam | 80
   branches/release/tools/build/v2/build/property.jam | 275 ++-
   branches/release/tools/build/v2/build/property_set.py | 90
   branches/release/tools/build/v2/build/readme.txt | 12
   branches/release/tools/build/v2/build/scanner.jam | 158 +-
   branches/release/tools/build/v2/build/targets.jam | 425 +++--
   branches/release/tools/build/v2/build/toolset.jam | 29
   branches/release/tools/build/v2/build/type.jam | 72
   branches/release/tools/build/v2/build/version.jam | 20
   branches/release/tools/build/v2/build/virtual-target.jam | 210 +-
   branches/release/tools/build/v2/build/virtual_target.py | 189 +-
   branches/release/tools/build/v2/build_system.py | 137 -
   branches/release/tools/build/v2/contrib/boost.jam | 293 ++--
   branches/release/tools/build/v2/doc/bjam.qbk | 122
   branches/release/tools/build/v2/doc/jamfile.jam | 4
   branches/release/tools/build/v2/doc/src/architecture.xml | 1088 ++++++++-------
   branches/release/tools/build/v2/doc/src/extending.xml | 7
   branches/release/tools/build/v2/doc/src/overview.xml | 173 +-
   branches/release/tools/build/v2/doc/src/path.xml | 1
   branches/release/tools/build/v2/doc/src/reference.xml | 80 +
   branches/release/tools/build/v2/engine/build.bat | 19
   branches/release/tools/build/v2/engine/build.jam | 141 +-
   branches/release/tools/build/v2/engine/build.sh | 34
   branches/release/tools/build/v2/engine/builtins.c | 1246 +++++++++---------
   branches/release/tools/build/v2/engine/builtins.h | 2
   branches/release/tools/build/v2/engine/bump_version.py | 130 +
   branches/release/tools/build/v2/engine/class.c | 68
   branches/release/tools/build/v2/engine/command.c | 56
   branches/release/tools/build/v2/engine/command.h | 23
   branches/release/tools/build/v2/engine/compile.c | 222 +--
   branches/release/tools/build/v2/engine/compile.h | 64
   branches/release/tools/build/v2/engine/constants.c | 117
   branches/release/tools/build/v2/engine/constants.h | 105
   branches/release/tools/build/v2/engine/debug.c | 30
   branches/release/tools/build/v2/engine/debug.h | 32
   branches/release/tools/build/v2/engine/execcmd.c | 88 +
   branches/release/tools/build/v2/engine/execcmd.h | 87 +
   branches/release/tools/build/v2/engine/execnt.c | 1359 +++++++++----------
   branches/release/tools/build/v2/engine/execunix.c | 712 +++++-----
   branches/release/tools/build/v2/engine/filent.c | 588 ++++----
   branches/release/tools/build/v2/engine/filesys.c | 323 ++++
   branches/release/tools/build/v2/engine/filesys.h | 56
   branches/release/tools/build/v2/engine/fileunix.c | 517 +++----
   branches/release/tools/build/v2/engine/frames.c | 16
   branches/release/tools/build/v2/engine/frames.h | 33
   branches/release/tools/build/v2/engine/function.c | 2661 ++++++++++++++++++++++-----------------
   branches/release/tools/build/v2/engine/hash.c | 271 +--
   branches/release/tools/build/v2/engine/hash.h | 57
   branches/release/tools/build/v2/engine/hcache.c | 177 +-
   branches/release/tools/build/v2/engine/hcache.h | 9
   branches/release/tools/build/v2/engine/hdrmacro.c | 97
   branches/release/tools/build/v2/engine/hdrmacro.h | 6
   branches/release/tools/build/v2/engine/headers.c | 141 -
   branches/release/tools/build/v2/engine/jam.c | 310 ++--
   branches/release/tools/build/v2/engine/jam.h | 81
   branches/release/tools/build/v2/engine/lists.c | 209 +-
   branches/release/tools/build/v2/engine/lists.h | 99
   branches/release/tools/build/v2/engine/make.c | 345 +++-
   branches/release/tools/build/v2/engine/make.h | 21
   branches/release/tools/build/v2/engine/make1.c | 1023 ++++++++------
   branches/release/tools/build/v2/engine/mem.h | 41
   branches/release/tools/build/v2/engine/modules.c | 91
   branches/release/tools/build/v2/engine/modules.h | 23
   branches/release/tools/build/v2/engine/modules/order.c | 191 +-
   branches/release/tools/build/v2/engine/modules/path.c | 37
   branches/release/tools/build/v2/engine/modules/property-set.c | 365 ++++-
   branches/release/tools/build/v2/engine/modules/regex.c | 212 ++
   branches/release/tools/build/v2/engine/modules/sequence.c | 102 +
   branches/release/tools/build/v2/engine/native.c | 41
   branches/release/tools/build/v2/engine/native.h | 39
   branches/release/tools/build/v2/engine/object.c | 209 +-
   branches/release/tools/build/v2/engine/object.h | 25
   branches/release/tools/build/v2/engine/option.h | 10
   branches/release/tools/build/v2/engine/output.c | 85
   branches/release/tools/build/v2/engine/output.h | 22
   branches/release/tools/build/v2/engine/parse.c | 2
   branches/release/tools/build/v2/engine/parse.h | 30
   branches/release/tools/build/v2/engine/patchlevel.h | 6
   branches/release/tools/build/v2/engine/pathnt.c | 30
   branches/release/tools/build/v2/engine/pathsys.h | 110
   branches/release/tools/build/v2/engine/pathunix.c | 570 --------
   branches/release/tools/build/v2/engine/regexp.c | 3
   branches/release/tools/build/v2/engine/regexp.h | 20
   branches/release/tools/build/v2/engine/rules.c | 262 ++-
   branches/release/tools/build/v2/engine/rules.h | 77
   branches/release/tools/build/v2/engine/scan.c | 87
   branches/release/tools/build/v2/engine/scan.h | 18
   branches/release/tools/build/v2/engine/search.c | 200 +-
   branches/release/tools/build/v2/engine/search.h | 6
   branches/release/tools/build/v2/engine/strings.c | 170 +-
   branches/release/tools/build/v2/engine/strings.h | 42
   branches/release/tools/build/v2/engine/subst.c | 139 +-
   branches/release/tools/build/v2/engine/timestamp.c | 299 ++-
   branches/release/tools/build/v2/engine/timestamp.h | 33
   branches/release/tools/build/v2/engine/variable.c | 166 +-
   branches/release/tools/build/v2/engine/variable.h | 20
   branches/release/tools/build/v2/hacking.txt | 24
   branches/release/tools/build/v2/kernel/bootstrap.jam | 179 +-
   branches/release/tools/build/v2/kernel/class.jam | 28
   branches/release/tools/build/v2/kernel/errors.jam | 47
   branches/release/tools/build/v2/kernel/modules.jam | 35
   branches/release/tools/build/v2/notes/README.txt | 8
   branches/release/tools/build/v2/roll.sh | 12
   branches/release/tools/build/v2/test/BoostBuild.py | 1138 +++++++++++-----
   branches/release/tools/build/v2/test/MockToolset.py | 92 +
   branches/release/tools/build/v2/test/TestCmd.py | 338 ++---
   branches/release/tools/build/v2/test/abs_workdir.py | 32
   branches/release/tools/build/v2/test/absolute_sources.py | 50
   branches/release/tools/build/v2/test/alias.py | 36
   branches/release/tools/build/v2/test/alternatives.py | 32
   branches/release/tools/build/v2/test/build_dir.py | 29
   branches/release/tools/build/v2/test/build_file.py | 108
   branches/release/tools/build/v2/test/build_no.py | 13
   branches/release/tools/build/v2/test/builtin_echo.py | 22
   branches/release/tools/build/v2/test/builtin_exit.py | 38
   branches/release/tools/build/v2/test/builtin_split_by_characters.py | 13
   branches/release/tools/build/v2/test/c_file.py | 2
   branches/release/tools/build/v2/test/chain.py | 16
   branches/release/tools/build/v2/test/clean.py | 54
   branches/release/tools/build/v2/test/collect_debug_info.py | 111 +
   branches/release/tools/build/v2/test/composite.py | 2
   branches/release/tools/build/v2/test/conditionals.py | 17
   branches/release/tools/build/v2/test/conditionals3.py | 2
   branches/release/tools/build/v2/test/conditionals_multiple.py | 292 ++--
   branches/release/tools/build/v2/test/configuration.py | 356 ++++-
   branches/release/tools/build/v2/test/copy_time.py | 33
   branches/release/tools/build/v2/test/core-language/test.jam | 63
   branches/release/tools/build/v2/test/core_action_output.py | 49
   branches/release/tools/build/v2/test/core_action_status.py | 26
   branches/release/tools/build/v2/test/core_actions_quietly.py | 42
   branches/release/tools/build/v2/test/core_arguments.py | 154 +-
   branches/release/tools/build/v2/test/core_at_file.py | 50
   branches/release/tools/build/v2/test/core_bindrule.py | 12
   branches/release/tools/build/v2/test/core_d12.py | 27
   branches/release/tools/build/v2/test/core_delete_module.py | 2
   branches/release/tools/build/v2/test/core_import_module.py | 8
   branches/release/tools/build/v2/test/core_language.py | 4
   branches/release/tools/build/v2/test/core_nt_cmd_line.py | 125 +
   branches/release/tools/build/v2/test/core_option_d2.py | 44
   branches/release/tools/build/v2/test/core_option_l.py | 23
   branches/release/tools/build/v2/test/core_option_n.py | 42
   branches/release/tools/build/v2/test/core_parallel_actions.py | 97
   branches/release/tools/build/v2/test/core_parallel_multifile_actions_1.py | 84
   branches/release/tools/build/v2/test/core_parallel_multifile_actions_2.py | 81
   branches/release/tools/build/v2/test/core_source_line_tracking.py | 15
   branches/release/tools/build/v2/test/core_typecheck.py | 20
   branches/release/tools/build/v2/test/core_update_now.py | 229 +++
   branches/release/tools/build/v2/test/core_variables_in_actions.py | 19
   branches/release/tools/build/v2/test/core_varnames.py | 4
   branches/release/tools/build/v2/test/default_build.py | 39
   branches/release/tools/build/v2/test/default_features.py | 2
   branches/release/tools/build/v2/test/default_toolset.py | 46
   branches/release/tools/build/v2/test/dependency_property.py | 10
   branches/release/tools/build/v2/test/dependency_test.py | 291 +++-
   branches/release/tools/build/v2/test/direct_request_test.py | 49
   branches/release/tools/build/v2/test/disambiguation.py | 2
   branches/release/tools/build/v2/test/dll_path.py | 82
   branches/release/tools/build/v2/test/double_loading.py | 15
   branches/release/tools/build/v2/test/example_libraries.py | 2
   branches/release/tools/build/v2/test/example_make.py | 7
   branches/release/tools/build/v2/test/expansion.py | 2
   branches/release/tools/build/v2/test/explicit.py | 22
   branches/release/tools/build/v2/test/free_features_request.py | 14
   branches/release/tools/build/v2/test/gcc_runtime.py | 35
   branches/release/tools/build/v2/test/generator_selection.py | 115
   branches/release/tools/build/v2/test/generators_test.py | 439 ++++++
   branches/release/tools/build/v2/test/implicit_dependency.py | 2
   branches/release/tools/build/v2/test/indirect_conditional.py | 83
   branches/release/tools/build/v2/test/inherit_toolset.py | 24
   branches/release/tools/build/v2/test/inherited_dependency.py | 2
   branches/release/tools/build/v2/test/inline.py | 18
   branches/release/tools/build/v2/test/lib_source_property.py | 2
   branches/release/tools/build/v2/test/library_chain.py | 70
   branches/release/tools/build/v2/test/library_order.py | 62
   branches/release/tools/build/v2/test/library_property.py | 2
   branches/release/tools/build/v2/test/load_order.py | 53
   branches/release/tools/build/v2/test/loop.py | 5
   branches/release/tools/build/v2/test/make_rule.py | 14
   branches/release/tools/build/v2/test/message.py | 4
   branches/release/tools/build/v2/test/module_actions.py | 132 +
   branches/release/tools/build/v2/test/ndebug.py | 20
   branches/release/tools/build/v2/test/no_type.py | 12
   branches/release/tools/build/v2/test/notfile.py | 28
   branches/release/tools/build/v2/test/ordered_include.py | 2
   branches/release/tools/build/v2/test/out_of_tree.py | 24
   branches/release/tools/build/v2/test/path_features.py | 157 +
   branches/release/tools/build/v2/test/prebuilt.py | 18
   branches/release/tools/build/v2/test/project_dependencies.py | 2
   branches/release/tools/build/v2/test/project_glob.py | 243 ++-
   branches/release/tools/build/v2/test/project_id.py | 178 ++
   branches/release/tools/build/v2/test/project_root_constants.py | 28
   branches/release/tools/build/v2/test/project_root_rule.py | 2
   branches/release/tools/build/v2/test/project_test3.py | 65
   branches/release/tools/build/v2/test/property_expansion.py | 15
   branches/release/tools/build/v2/test/rebuilds.py | 49
   branches/release/tools/build/v2/test/regression.py | 47
   branches/release/tools/build/v2/test/relative_sources.py | 2
   branches/release/tools/build/v2/test/remove_requirement.py | 2
   branches/release/tools/build/v2/test/rescan_header.py | 227 ++
   branches/release/tools/build/v2/test/resolution.py | 18
   branches/release/tools/build/v2/test/scanner_causing_rebuilds.py | 2
   branches/release/tools/build/v2/test/searched_lib.py | 42
   branches/release/tools/build/v2/test/skipping.py | 21
   branches/release/tools/build/v2/test/sort_rule.py | 45
   branches/release/tools/build/v2/test/source_locations.py | 2
   branches/release/tools/build/v2/test/space_in_path.py | 17
   branches/release/tools/build/v2/test/stage.py | 109 -
   branches/release/tools/build/v2/test/standalone.py | 24
   branches/release/tools/build/v2/test/startup_v2.py | 139 +
   branches/release/tools/build/v2/test/static_and_shared_library.py | 10
   branches/release/tools/build/v2/test/symlink.py | 2
   branches/release/tools/build/v2/test/tag.py | 70
   branches/release/tools/build/v2/test/test_all.py | 348 ++--
   branches/release/tools/build/v2/test/test_rc.py | 74
   branches/release/tools/build/v2/test/test_result_dumping.py | 20
   branches/release/tools/build/v2/test/testing_support.py | 2
   branches/release/tools/build/v2/test/timedata.py | 74
   branches/release/tools/build/v2/test/tree.py | 285 +++-
   branches/release/tools/build/v2/test/unit_test.py | 4
   branches/release/tools/build/v2/test/unit_tests.py | 10
   branches/release/tools/build/v2/test/unused.py | 76
   branches/release/tools/build/v2/test/use_requirements.py | 110
   branches/release/tools/build/v2/test/using.py | 22
   branches/release/tools/build/v2/test/wrapper.py | 2
   branches/release/tools/build/v2/test/wrong_project.py | 14
   branches/release/tools/build/v2/test/zlib.py | 77
   branches/release/tools/build/v2/tools/auto-index.jam | 12
   branches/release/tools/build/v2/tools/boostbook.jam | 1059 ++++++++-------
   branches/release/tools/build/v2/tools/builtin.jam | 26
   branches/release/tools/build/v2/tools/cast.jam | 6
   branches/release/tools/build/v2/tools/clang-linux.jam | 10
   branches/release/tools/build/v2/tools/common.jam | 111
   branches/release/tools/build/v2/tools/cray.jam | 3
   branches/release/tools/build/v2/tools/darwin.jam | 13
   branches/release/tools/build/v2/tools/doxygen.jam | 491 +++---
   branches/release/tools/build/v2/tools/gcc.py | 4
   branches/release/tools/build/v2/tools/make.jam | 25
   branches/release/tools/build/v2/tools/message.jam | 23
   branches/release/tools/build/v2/tools/msvc.jam | 126 +
   branches/release/tools/build/v2/tools/msvc.py | 2
   branches/release/tools/build/v2/tools/notfile.jam | 41
   branches/release/tools/build/v2/tools/pathscale.jam | 14
   branches/release/tools/build/v2/tools/pgi.jam | 2
   branches/release/tools/build/v2/tools/python.jam | 15
   branches/release/tools/build/v2/tools/qcc.jam | 4
   branches/release/tools/build/v2/tools/qt4.jam | 15
   branches/release/tools/build/v2/tools/rc.jam | 81
   branches/release/tools/build/v2/tools/stage.jam | 125
   branches/release/tools/build/v2/tools/stlport.jam | 52
   branches/release/tools/build/v2/tools/testing-aux.jam | 30
   branches/release/tools/build/v2/tools/testing.jam | 35
   branches/release/tools/build/v2/tools/testing.py | 5
   branches/release/tools/build/v2/tools/types/cpp.jam | 28
   branches/release/tools/build/v2/tools/xsltproc-config.jam | 41
   branches/release/tools/build/v2/tools/xsltproc.jam | 55
   branches/release/tools/build/v2/tools/zlib.jam | 259 ++
   branches/release/tools/build/v2/util/assert.jam | 32
   branches/release/tools/build/v2/util/doc.jam | 17
   branches/release/tools/build/v2/util/indirect.jam | 14
   branches/release/tools/build/v2/util/path.jam | 290 +--
   branches/release/tools/build/v2/util/print.jam | 46
   branches/release/tools/build/v2/util/regex.jam | 14
   branches/release/tools/build/v2/util/sequence.jam | 4
   branches/release/tools/build/v2/util/utility.jam | 32
   277 files changed, 18081 insertions(+), 14701 deletions(-)

Modified: branches/release/Jamroot
==============================================================================
--- branches/release/Jamroot (original)
+++ branches/release/Jamroot 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,7 +9,7 @@
 
 # Usage:
 #
-# bjam [options] [properties] [install|stage]
+# b2 [options] [properties] [install|stage]
 #
 # Builds and installs Boost.
 #

Modified: branches/release/status/explicit-failures-markup.xml
==============================================================================
--- branches/release/status/explicit-failures-markup.xml (original)
+++ branches/release/status/explicit-failures-markup.xml 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -468,16 +468,14 @@
 
     <!-- build -->
     <library name="build">
- <test name="timedata">
- <mark-failure>
- <toolset name="msvc-7.1"/>
- <toolset name="msvc-8.0"/>
- <toolset name="msvc-9.0"/>
- <note author="Vladimir Prus">
- See https://zigzag.lvk.cs.msu.su:7813/boost.build/ticket/218
- </note>
- </mark-failure>
- </test>
+ <mark-expected-failures>
+ <test name="collect_debug_info"/>
+ <toolset name="*"/>
+ <note author="Jurko Gospodnetić">
+ Temporarily enabled and always failing test used for collecting
+ additional feedback from the testing site.
+ </note>
+ </mark-expected-failures>
     </library>
 
     <!-- chrono -->

Modified: branches/release/tools/build/v2/bootstrap.sh
==============================================================================
--- branches/release/tools/build/v2/bootstrap.sh (original)
+++ branches/release/tools/build/v2/bootstrap.sh 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,9 +8,9 @@
 
 # boostinspect:notab - Tabs are required for the Makefile.
 
-BJAM=""
+B2=""
 TOOLSET=""
-BJAM_CONFIG=""
+B2_CONFIG=""
 
 for option
 do
@@ -42,7 +42,7 @@
 
 Configuration:
   -h, --help display this help and exit
- --with-bjam=BJAM use existing Boost.Jam executable (bjam)
+ --with-b2=B2 use existing Boost.Build executable (b2)
                             [automatically built]
   --with-toolset=TOOLSET use specific Boost.Build toolset
                             [automatically detected]
@@ -92,8 +92,8 @@
 
 rm -f config.log
 
-# Build bjam
-if test "x$BJAM" = x; then
+# Build b2
+if test "x$B2" = x; then
   echo -n "Bootstrapping the build engine with toolset $TOOLSET... "
   pwd=`pwd`
   (cd "$my_dir/engine" && ./build.sh "$TOOLSET") > bootstrap.log 2>&1
@@ -105,9 +105,9 @@
   fi
   cd "$pwd"
   arch=`cd $my_dir/engine && ./bootstrap/jam0 -d0 -f build.jam --toolset=$TOOLSET --toolset-root= --show-locate-target && cd ..`
- BJAM="$my_dir/engine/$arch/b2"
- echo "engine/$arch/bjam"
- cp "$BJAM" .
+ B2="$my_dir/engine/$arch/b2"
+ echo "engine/$arch/b2"
+ cp "$B2" .
   cp "$my_dir/engine/$arch/bjam" .
 fi
 

Modified: branches/release/tools/build/v2/build-system.jam
==============================================================================
--- branches/release/tools/build/v2/build-system.jam (original)
+++ branches/release/tools/build/v2/build-system.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 # Copyright 2006, 2007 Rene Rivera
 # Copyright 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # This file is part of Boost Build version 2. You can think of it as forming the
 # main() routine. It is invoked by the bootstrapping code in bootstrap.jam.
@@ -10,13 +11,16 @@
 import build-request ;
 import builtin ;
 import "class" : new ;
-import errors ;
+import configure ;
+import config-cache ;
 import feature ;
+import generators ;
 import make ;
 import modules ;
 import os ;
 import path ;
 import project ;
+import property ;
 import property-set ;
 import regex ;
 import sequence ;
@@ -25,8 +29,7 @@
 import utility ;
 import version ;
 import virtual-target ;
-import generators ;
-import configure ;
+
 
 ################################################################################
 #
@@ -41,22 +44,6 @@
 # locating and loading Boost Build configuration files.
 .debug-config = [ MATCH ^(--debug-configuration)$ : $(.argv) ] ;
 
-# Legacy option doing too many things, some of which are not even documented.
-# Should be phased out.
-# * Disables loading site and user configuration files.
-# * Disables auto-configuration for toolsets specified explicitly on the
-# command-line.
-# * Causes --toolset command-line options to be ignored.
-# * Prevents the default toolset from being used even if no toolset has been
-# configured at all.
-.legacy-ignore-config = [ MATCH ^(--ignore-config)$ : $(.argv) ] ;
-
-# The cleaning is tricky. Say, if user says 'bjam --clean foo' where 'foo' is a
-# directory, then we want to clean targets which are in 'foo' as well as those
-# in any children Jamfiles under foo but not in any unrelated Jamfiles. To
-# achieve this we collect a list of projects under which cleaning is allowed.
-.project-targets = ;
-
 # Virtual targets obtained when building main targets references on the command
 # line. When running 'bjam --clean main_target' we want to clean only files
 # belonging to that main target so we need to record which targets are produced
@@ -134,13 +121,17 @@
 #
 local rule actual-clean-targets ( )
 {
- # Construct a list of projects explicitly detected as targets on this build
- # system run. These are the projects under which cleaning is allowed.
+ # The cleaning is tricky. Say, if user says 'bjam --clean foo' where 'foo'
+ # is a directory, then we want to clean targets which are in 'foo' as well
+ # as those in any children Jamfiles under foo but not in any unrelated
+ # Jamfiles. To achieve this we first mark all projects explicitly detected
+ # as targets for this build system run as needing to be cleaned.
     for local t in $(targets)
     {
         if [ class.is-a $(t) : project-target ]
         {
- .project-targets += [ $(t).project-module ] ;
+ local project = [ $(t).project-module ] ;
+ .should-clean-project.$(project) = true ;
         }
     }
 
@@ -157,16 +148,13 @@
     local to-clean ;
     for local t in [ virtual-target.all-targets ]
     {
+ # Remove only derived targets and only those asked to be cleaned,
+ # whether directly or by belonging to one of the removed projects.
         local p = [ $(t).project ] ;
-
- # Remove only derived targets.
- if [ $(t).action ]
+ if [ $(t).action ] && ( $(t) in $(targets-to-clean) ||
+ [ should-clean-project [ $(p).project-module ] ] )
         {
- if $(t) in $(targets-to-clean) ||
- [ should-clean-project [ $(p).project-module ] ] = true
- {
- to-clean += $(t) ;
- }
+ to-clean += $(t) ;
         }
     }
 
@@ -235,8 +223,10 @@
 {
     if $(.debug-config)
     {
- ECHO "notice: Searching" "$(path)" "for" "$(module-name)"
- "configuration file" "$(filename)" "." ;
+ local path-string = $(path) ;
+ if $(path-string) = "" { path-string = . ; }
+ ECHO notice: Searching '$(path-string)' for $(module-name)
+ configuration file '$(filename)'. ;
     }
     local where = [ GLOB $(path) : $(filename) ] ;
     if $(where)
@@ -244,31 +234,35 @@
         where = [ NORMALIZE_PATH $(where[1]) ] ;
         if $(.debug-config)
         {
- ECHO "notice: Loading" "$(module-name)" "configuration file"
- "$(filename)" "from" $(where) "." ;
+ local where-string = $(where:D) ;
+ if $(where-string) = "" { where-string = . ; }
+ where-string = '$(where-string)' ;
+ ECHO notice: Loading $(module-name) configuration file '$(filename)'
+ from $(where-string:J=" "). ;
         }
 
- # Set source location so that path-constant in config files
- # with relative paths work. This is of most importance
- # for project-config.jam, but may be used in other
- # config files as well.
+ # Set source location so that path-constant in config files with
+ # relative paths work. This is of most importance for
+ # project-config.jam, but may be used in other config files as well.
         local attributes = [ project.attributes $(module-name) ] ;
         $(attributes).set source-location : $(where:D) : exact ;
         modules.load $(module-name) : $(filename) : $(path) ;
         project.load-used-projects $(module-name) ;
     }
- else
+ else if $(must-find) || $(.debug-config)
     {
+ local path-string = $(path) ;
+ if $(path-string) = "" { path-string = . ; }
+ path-string = '$(path-string)' ;
+ path-string = $(path-string:J=" ") ;
         if $(must-find)
         {
- errors.user-error "Configuration file" "$(filename)" "not found in"
- "$(path)" "." ;
- }
- if $(.debug-config)
- {
- ECHO "notice:" "Configuration file" "$(filename)" "not found in"
- "$(path)" "." ;
+ import errors ;
+ errors.user-error Configuration file '$(filename)' not found "in"
+ $(path-string). ;
         }
+ ECHO notice: Configuration file '$(filename)' not found "in"
+ $(path-string). ;
     }
     return $(where) ;
 }
@@ -287,8 +281,7 @@
 # Always named site-config.jam. Will only be found if located on the system
 # root path (Windows), /etc (non-Windows), user's home folder or the Boost Build
 # path, in that order. Not loaded in case the test-config configuration file is
-# loaded or either the --ignore-site-config or the --ignore-config command-line
-# option is specified.
+# loaded or the --ignore-site-config command-line option is specified.
 #
 # -- user-config --
 # Named user-config.jam by default or may be named explicitly using the
@@ -296,10 +289,13 @@
 # variable. If named explicitly the file is looked for from the current working
 # directory and if the default one is used then it is searched for in the
 # user's home directory and the Boost Build path, in that order. Not loaded in
-# case either the test-config configuration file is loaded, --ignore-config
-# command-line option is specified or an empty file name is explicitly
-# specified. If the file name has been given explicitly then the file must
-# exist.
+# case either the test-config configuration file is loaded or an empty file name
+# is explicitly specified. If the file name has been given explicitly then the
+# file must exist.
+#
+# -- project-config --
+# Always named project-config.jam. Looked up in the current working folder and
+# then upwards through its parents up to the root folder.
 #
 # Test configurations have been added primarily for use by Boost Build's
 # internal unit testing system but may be used freely in other places as well.
@@ -310,12 +306,6 @@
     local ignore-site-config =
         [ MATCH ^(--ignore-site-config)$ : $(.argv) ] ;
 
- if $(.legacy-ignore-config) && $(.debug-config)
- {
- ECHO "notice: Regular site and user configuration files will be ignored" ;
- ECHO "notice: due to the --ignore-config command-line option." ;
- }
-
     initialize-config-module test-config ;
     local test-config = [ MATCH ^--test-config=(.*)$ : $(.argv) ] ;
     local uq = [ MATCH \"(.*)\" : $(test-config) ] ;
@@ -325,11 +315,11 @@
     }
     if $(test-config)
     {
- local where =
- [ load-config test-config : $(test-config:BS) : $(test-config:D) ] ;
+ local where = [ load-config test-config : $(test-config:BS) :
+ $(test-config:D) ] ;
         if $(where)
         {
- if $(.debug-config) && ! $(.legacy-ignore-config)
+ if $(.debug-config)
             {
                 ECHO "notice: Regular site and user configuration files will" ;
                 ECHO "notice: be ignored due to the test configuration being"
@@ -349,20 +339,20 @@
         site-path = [ modules.peek : SystemRoot ] $(user-path) ;
     }
 
- if $(ignore-site-config) && !$(.legacy-ignore-config)
+ if $(.debug-config) && ! $(test-config) && $(ignore-site-config)
     {
         ECHO "notice: Site configuration files will be ignored due to the" ;
         ECHO "notice: --ignore-site-config command-line option." ;
     }
 
     initialize-config-module site-config ;
- if ! $(test-config) && ! $(ignore-site-config) && ! $(.legacy-ignore-config)
+ if ! $(test-config) && ! $(ignore-site-config)
     {
         load-config site-config : site-config.jam : $(site-path) ;
     }
 
     initialize-config-module user-config ;
- if ! $(test-config) && ! $(.legacy-ignore-config)
+ if ! $(test-config)
     {
         local user-config = [ MATCH ^--user-config=(.*)$ : $(.argv) ] ;
         user-config = $(user-config[-1]) ;
@@ -386,8 +376,8 @@
 
                 if $(.debug-config)
                 {
- ECHO "notice: Loading explicitly specified user"
- "configuration file:" ;
+ ECHO notice: Loading explicitly specified user configuration
+ file: ;
                     ECHO " $(user-config)" ;
                 }
 
@@ -401,17 +391,16 @@
         }
         else if $(.debug-config)
         {
- ECHO "notice: User configuration file loading explicitly disabled." ;
+ ECHO notice: User configuration file loading explicitly disabled. ;
         }
     }
-
- # We look for project-config.jam from "." upward.
- # I am not sure this is 100% right decision, we might as well check for
- # it only alonside the Jamroot file. However:
- #
- # - We need to load project-root.jam before Jamroot
- # - We probably would need to load project-root.jam even if there's no
- # Jamroot - e.g. to implement automake-style out-of-tree builds.
+
+ # We look for project-config.jam from "." upward. I am not sure this is 100%
+ # right decision, we might as well check for it only alongside the Jamroot
+ # file. However:
+ # - We need to load project-config.jam before Jamroot
+ # - We probably need to load project-config.jam even if there is no Jamroot
+ # - e.g. to implement automake-style out-of-tree builds.
     local file = [ path.glob "." : project-config.jam ] ;
     if ! $(file)
     {
@@ -420,8 +409,10 @@
     if $(file)
     {
         initialize-config-module project-config : $(file:D) ;
- load-config project-config : project-config.jam : $(file:D) ;
- }
+ load-config project-config : project-config.jam : $(file:D) ;
+ }
+
+ project.end-load ;
 }
 
 
@@ -439,29 +430,17 @@
     for local t in $(option-toolsets) $(feature-toolsets)
     {
         # Parse toolset-version/properties.
- local (t-v,t,v) = [ MATCH (([^-/]+)-?([^/]+)?)/?.* : $(t) ] ;
- local toolset-version = $((t-v,t,v)[1]) ;
- local toolset = $((t-v,t,v)[2]) ;
- local version = $((t-v,t,v)[3]) ;
-
- if $(.debug-config)
- {
- ECHO notice: [cmdline-cfg] Detected command-line request for
- $(toolset-version): "toolset=" $(toolset) "version="
- $(version) ;
- }
-
- # If the toolset is not known, configure it now.
+ local toolset = [ MATCH ([^/]+)/?.* : $(t) ] ;
+ local properties = [ feature.expand-subfeatures <toolset>$(toolset) : true ] ;
+ local toolset-property = [ property.select <toolset> : $(properties) ] ;
         local known ;
- if $(toolset) in [ feature.values <toolset> ]
+ if $(toolset-property:G=) in [ feature.values <toolset> ]
         {
             known = true ;
         }
- if $(known) && $(version) && ! [ feature.is-subvalue toolset
- : $(toolset) : version : $(version) ]
- {
- known = ;
- }
+
+ # If the toolset is not known, configure it now.
+
         # TODO: we should do 'using $(toolset)' in case no version has been
         # specified and there are no versions defined for the given toolset to
         # allow the toolset to configure its default version. For this we need
@@ -475,24 +454,17 @@
         {
             if $(.debug-config)
             {
- ECHO "notice: [cmdline-cfg] toolset $(toolset-version) not"
+ ECHO "notice: [cmdline-cfg] toolset $(toolset) not"
                     "previously configured; attempting to auto-configure now" ;
             }
- toolset.using $(toolset) : $(version) ;
- }
- else
- {
- if $(.debug-config)
- {
- ECHO notice: [cmdline-cfg] toolset $(toolset-version) already
- configured ;
- }
+ local t,v = [ MATCH ([^-]+)-?(.+)? : $(toolset) ] ;
+ toolset.using $(t,v[1]) : $(t,v[2]) ;
         }
 
         # Make sure we get an appropriate property into the build request in
         # case toolset has been specified using the "--toolset=..." command-line
         # option form.
- if ! $(t) in $(.argv) && ! $(t) in $(feature-toolsets)
+ if ! $(t) in $(.argv) $(feature-toolsets)
         {
             if $(.debug-config)
             {
@@ -507,24 +479,21 @@
 }
 
 
-# Returns 'true' if the given 'project' is equal to or is a (possibly indirect)
-# child to any of the projects requested to be cleaned in this build system run.
-# Returns 'false' otherwise. Expects the .project-targets list to have already
-# been constructed.
+# Returns whether the given project (identifed by its project module) should be
+# cleaned because it or any of its parent projects have already been marked as
+# needing to be cleaned in this build. As an optimization, will explicitly mark
+# all encountered project needing to be cleaned in case thay have not already
+# been marked so.
 #
 local rule should-clean-project ( project )
 {
- if ! $(.should-clean-project.$(project))
+ if ! $(.should-clean-project.$(project))-is-defined
     {
- local r = false ;
- if $(project) in $(.project-targets)
- {
- r = true ;
- }
- else
+ local r = "" ;
+ if ! [ project.is-jamroot-module $(project) ]
         {
             local parent = [ project.attribute $(project) parent-module ] ;
- if $(parent) && $(parent) != user-config
+ if $(parent)
             {
                 r = [ should-clean-project $(parent) ] ;
             }
@@ -543,39 +512,35 @@
 #
 ################################################################################
 
-{
+{
     if --version in $(.argv)
     {
         version.print ;
         EXIT ;
     }
-
- version.verify-engine-version ;
-
- load-configuration-files ;
 
- local extra-properties ;
- # Note that this causes --toolset options to be ignored if --ignore-config
- # is specified.
- if ! $(.legacy-ignore-config)
- {
- extra-properties = [ process-explicit-toolset-requests ] ;
- }
+ version.verify-engine-version ;
 
+ load-configuration-files ;
+
+ # Load explicitly specified toolset modules.
+ local extra-properties = [ process-explicit-toolset-requests ] ;
 
- # We always load project in "." so that 'use-project' directives have any
- # chance of being seen. Otherwise, we would not be able to refer to
- # subprojects using target ids.
+ # Load the actual project build script modules. We always load the project
+ # in the current folder so 'use-project' directives have any chance of being
+ # seen. Otherwise, we would not be able to refer to subprojects using target
+ # ids.
     local current-project ;
- if [ project.find "." : "." ]
     {
- current-project = [ project.target [ project.load "." ] ] ;
+ local current-module = [ project.find "." : "." ] ;
+ if $(current-module)
+ {
+ current-project = [ project.target $(current-module) ] ;
+ }
     }
 
-
- # In case there are no toolsets currently defined makes the build run using
- # the default toolset.
- if ! $(.legacy-ignore-config) && ! [ feature.values <toolset> ]
+ # Load the default toolset module if no other has already been specified.
+ if ! [ feature.values <toolset> ]
     {
         local default-toolset = $(.default-toolset) ;
         local default-toolset-version = ;
@@ -593,7 +558,7 @@
             else if [ os.name ] = MACOSX
             {
                 default-toolset = darwin ;
- }
+ }
         }
 
         ECHO "warning: No toolsets are configured." ;
@@ -609,6 +574,11 @@
 
     # Parse command line for targets and properties. Note that this requires
     # that all project files already be loaded.
+ # FIXME: This is not entirely true. Additional project files may be loaded
+ # only later via the project.find() rule when dereferencing encountered
+ # target ids containing explicit project references. See what to do about
+ # those as such 'lazy loading' may cause problems that are then extremely
+ # difficult to debug.
     local build-request = [ build-request.from-command-line $(.argv)
         $(extra-properties) ] ;
     local target-ids = [ $(build-request).get-at 1 ] ;
@@ -638,9 +608,9 @@
     # Check that we actually found something to build.
     if ! $(current-project) && ! $(target-ids)
     {
- errors.user-error "error: no Jamfile in current directory found, and no"
- "target references specified." ;
- EXIT ;
+ import errors ;
+ errors.user-error no Jamfile "in" current directory found, and no target
+ references specified. ;
     }
 
 
@@ -707,23 +677,24 @@
     {
         targets += [ project.target [ project.module-name "." ] ] ;
     }
-
- if [ option.get dump-generators : : true ]
+
+ if [ option.get dump-generators : : true ]
     {
         generators.dump ;
     }
-
- # We wish to put config.log in the build directory corresponding
- # to Jamroot, so that the location does not differ depending on
- # directory where we do build. The amount of indirection necessary
- # here is scary.
+
+ # We wish to put config.log in the build directory corresponding to Jamroot,
+ # so that the location does not differ depending on the directory we run the
+ # build from. The amount of indirection necessary here is scary.
     local first-project = [ $(targets[0]).project ] ;
     local first-project-root-location = [ $(first-project).get project-root ] ;
- local first-project-root-module = [ project.load $(first-project-root-location) ] ;
- local first-project-root = [ project.target $(first-project-root-module) ] ;
+ local first-project-root-module = [ project.load
+ $(first-project-root-location) ] ;
+ local first-project-root = [ project.target $(first-project-root-module) ] ;
     local first-build-build-dir = [ $(first-project-root).build-dir ] ;
     configure.set-log-file $(first-build-build-dir)/config.log ;
-
+ config-cache.load $(first-build-build-dir)/project-cache.jam ;
+
     # Now that we have a set of targets to build and a set of property sets to
     # build the targets with, we can start the main build process by using each
     # property set to generate virtual targets from all of our listed targets
@@ -749,6 +720,8 @@
         actual-targets += [ $(t).actualize ] ;
     }
 
+ config-cache.save ;
+
 
     # If XML data output has been requested prepare additional rules and targets
     # so we can hook into Jam to collect build data while its building and have
@@ -827,7 +800,8 @@
             # constituent action fails and regenerate the xml on every bjam run.
             INCLUDES $(xml-file) : $(constituents) ;
             ALWAYS $(xml-file) ;
- __ACTION_RULE__ on $(xml-file) = build-system.out-xml.generate-action ;
+ __ACTION_RULE__ on $(xml-file) =
+ build-system.out-xml.generate-action ;
             out-xml.generate $(xml-file) ;
         }
 
@@ -920,7 +894,7 @@
             __ACTION_RULE__ = build-system.out-xml.collect
                 [ modules.peek build-system : .out-xml ] ;
         }
-
+
         IMPORT
             build-system :
             out-xml.collect
@@ -936,7 +910,7 @@
     {
         modules.poke : PARALLELISM : $(j) ;
     }
-
+
     local k = [ option.get keep-going : true : true ] ;
     if $(k) in "on" "yes" "true"
     {
@@ -948,10 +922,9 @@
     }
     else
     {
- ECHO "error: Invalid value for the --keep-going option" ;
- EXIT ;
+ EXIT "error: Invalid value for the --keep-going option" ;
     }
-
+
     # The 'all' pseudo target is not strictly needed expect in the case when we
     # use it below but people often assume they always have this target
     # available and do not declare it themselves before use which may cause
@@ -980,29 +953,29 @@
         UPDATE clean ;
     }
     else
- {
- configure.print-configure-checks-summary ;
-
+ {
+ configure.print-configure-checks-summary ;
+
         if $(.pre-build-hook)
         {
             $(.pre-build-hook) ;
         }
-
+
         DEPENDS all : $(actual-targets) ;
         if UPDATE_NOW in [ RULENAMES ]
- {
+ {
             local ok = [ UPDATE_NOW all $(.out-xml) ] ;
             if $(.post-build-hook)
             {
                 $(.post-build-hook) $(ok) ;
             }
- # Prevent automatic update of the 'all' target, now that
- # we have explicitly updated what we wanted.
+ # Prevent automatic update of the 'all' target, now that we have
+ # explicitly updated what we wanted.
             UPDATE ;
         }
         else
         {
             UPDATE all $(.out-xml) ;
- }
+ }
     }
 }

Modified: branches/release/tools/build/v2/build/ac.jam
==============================================================================
--- branches/release/tools/build/v2/build/ac.jam (original)
+++ branches/release/tools/build/v2/build/ac.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,4 +1,5 @@
 # Copyright (c) 2010 Vladimir Prus.
+# Copyright (c) 2013 Steven Watanabe
 #
 # Use, modification and distribution is subject to the Boost Software
 # License Version 1.0. (See accompanying file LICENSE_1_0.txt or
@@ -10,106 +11,109 @@
 import "class" ;
 import errors ;
 import configure ;
+import project ;
+import virtual-target ;
+import generators ;
+import property ;
+import print ;
 
-rule find-include-path ( variable : properties : header
- : provided-path ? )
+project.initialize $(__name__) ;
+.project = [ project.current ] ;
+project ac ;
+
+rule generate-include ( target : sources * : properties * )
+{
+ local header = [ property.select <include> : $(properties) ] ;
+ print.output $(target) ;
+ print.text "#include <$(header:G=)>" : true ;
+}
+
+rule generate-main ( target : sources * : properties * )
+{
+ print.output $(target) ;
+ print.text "int main() {}" : true ;
+}
+
+rule find-include-path ( properties : header : provided-path ? )
 {
- # FIXME: document which properties affect this function by
- # default.
- local target-os = [ $(properties).get <target-os> ] ;
- properties = [ property-set.create <target-os>$(toolset) ] ;
- if $($(variable)-$(properties))
+ if $(provided-path) && [ path.exists [ path.root $(header) $(provided-path) ] ]
     {
- return $($(variable)-$(properties)) ;
+ return $(provided-path) ;
     }
     else
     {
- provided-path ?= [ modules.peek : $(variable) ] ;
- includes = $(provided-path) ;
- includes += [ $(properties).get <include> ] ;
- if [ $(properties).get <target-os> ] != windows
+ local a = [ class.new action : ac.generate-include : [ property-set.create <include>$(header) ] ] ;
+ local cpp = [ class.new file-target $(header).cpp exact : CPP : $(.project) : $(a) ] ;
+ cpp = [ virtual-target.register $(cpp) ] ;
+ local result = [ generators.construct $(.project) $(header) : OBJ : $(properties) : $(cpp) : true ] ;
+ local jam-targets ;
+ for t in $(result[2-])
         {
- # FIXME: use sysroot
- includes += /usr/include ;
+ jam-targets += [ $(t).actualize ] ;
         }
-
- local result ;
- while ! $(result) && $(includes)
- {
- local f = [ path.root $(header) $(includes[1]) ] ;
- ECHO "Checking " $(f) ;
- if [ path.exists $(f) ]
- {
- result = $(includes[1]) ;
- }
- else if $(provided-path)
- {
- errors.user-error "Could not find header" $(header)
- : "in the user-specified directory" $(provided-path) ;
- }
- includes = $(includes[2-]) ;
- }
- $(variable)-$(properties) = $(result) ;
- return $(result) ;
- }
-}
-
-rule find-library ( variable : properties : names + : provided-path ? )
-{
- local target-os = [ $(properties).get <target-os> ] ;
- properties = [ property-set.create <target-os>$(toolset) ] ;
- if $($(variable)-$(properties))
+ if [ UPDATE_NOW $(jam-targets) : [ modules.peek configure : .log-fd ]
+ : ignore-minus-n : ignore-minus-q ]
+ {
+ return %default ;
+ }
+ }
+}
+
+rule construct-library ( name : property-set : provided-path ? )
+{
+ property-set = [ $(property-set).refine [ property-set.create $(link-opt) ] ] ;
+ local lib-props = [ $(property-set).add-raw <name>$(name) <search>$(provided-path) ] ;
+ return [ generators.construct $(.project) lib-$(name)
+ : SEARCHED_LIB : $(lib-props) : : true ] ;
+}
+
+
+rule find-library ( properties : names + : provided-path ? )
+{
+ local result ;
+ if ! $(.main.cpp)
     {
- return $($(variable)-$(properties)) ;
+ local a = [ class.new action : ac.generate-main :
+ [ property-set.empty ] ] ;
+ .main.cpp = [ virtual-target.register
+ [ class.new file-target main.cpp exact
+ : CPP : $(.project) : $(a) ] ] ;
+ }
+ if [ $(properties).get <link> ] = shared
+ {
+ link-opts = <link>shared <link>static ;
     }
     else
     {
- provided-path ?= [ modules.peek : $(variable) ] ;
- paths = $(provided-path) ;
- paths += [ $(properties).get <library-path> ] ;
- if [ $(properties).get <target-os> ] != windows
+ link-opts = <link>static <link>shared ;
+ }
+ while $(link-opts)
+ {
+ local names-iter = $(names) ;
+ properties = [ $(properties).refine [ property-set.create $(link-opts[1]) ] ] ;
+ while $(names-iter)
         {
- paths += /usr/lib /usr/lib32 /usr/lib64 ;
+ local name = $(names-iter[1]) ;
+ local lib = [ construct-library $(name) : $(properties) : $(provided-path) ] ;
+ local test = [ generators.construct $(.project) $(name) : EXE
+ : [ $(properties).add $(lib[1]) ] : $(.main.cpp) $(lib[2-])
+ : true ] ;
+ local jam-targets ;
+ for t in $(test[2-])
+ {
+ jam-targets += [ $(t).actualize ] ;
+ }
+ if [ UPDATE_NOW $(jam-targets) : [ modules.peek configure : .log-fd ]
+ : ignore-minus-n : ignore-minus-q ]
+ {
+ result = $(name) $(link-opts[1]) ;
+ names-iter = ; link-opts = ; # break
+ }
+ names-iter = $(names-iter[2-]) ;
         }
-
- local result ;
- while ! $(result) && $(paths)
- {
- while ! $(result) && $(names)
- {
- local f ;
- if $(target-os) = windows
- {
- f = $(paths[1])/$(names[1]).lib ;
- if [ path.exists $(f) ]
- {
- result = $(f) ;
- }
- }
- else
- {
- # FIXME: check for .a as well, depending on
- # the 'link' feature.
- f = $(paths[1])/lib$(names[1]).so ;
- ECHO "CHECKING $(f) " ;
- if [ path.exists $(f) ]
- {
- result = $(f) ;
- }
- }
- if ! $(result) && $(provided-path)
- {
- errors.user-error "Could not find either of: " $(names)
- : "in the user-specified directory" $(provided-path) ;
-
- }
- names = $(names[2-]) ;
- }
- paths = $(paths[2-]) ;
- }
- $(variable)-$(properties) = $(result) ;
- return $(result) ;
+ link-opts = $(link-opts[2-]) ;
     }
+ return $(result) ;
 }
 
 class ac-library : basic-target
@@ -119,13 +123,13 @@
     import virtual-target ;
     import ac ;
     import configure ;
+ import config-cache ;
 
- rule __init__ ( name : project : * : * )
+ rule __init__ ( name : project : requirements * : include-path ? : library-path ? : library-name ? )
     {
- basic-target.__init__ $(name) : $(project) : $(sources)
- : $(requirements) ;
+ basic-target.__init__ $(name) : $(project) : : $(requirements) ;
         
- reconfigure $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ reconfigure $(include-path) : $(library-path) : $(library-name) ;
     }
     
     rule set-header ( header )
@@ -137,62 +141,163 @@
     {
         self.default-names = $(names) ;
     }
-
- rule reconfigure ( * : * )
+
+ rule reconfigure ( include-path ? : library-path ? : library-name ? )
+ {
+ if $(include-path) || $(library-path) || $(library-name)
+ {
+ check-not-configured ;
+
+ self.include-path = $(include-path) ;
+ self.library-path = $(library-path) ;
+ self.library-name = $(library-name) ;
+ }
+ }
+
+ rule set-target ( target )
+ {
+ check-not-configured ;
+ self.target = $(target) ;
+ }
+
+ rule check-not-configured ( )
+ {
+ if $(self.include-path) || $(self.library-path) || $(self.library-name) || $(self.target)
+ {
+ errors.user-error [ name ] "is already configured" ;
+ }
+ }
+
+ rule construct ( name : sources * : property-set )
     {
- ECHO "XXX" $(1) ;
- if ! $(1)
+ if $(self.target)
         {
- # This is 'using xxx ;'. Nothing to configure, really.
+ return [ $(self.target).generate $(property-set) ] ;
         }
         else
         {
- for i in 1 2 3 4 5 6 7 8 9
+ local use-environment ;
+ if ! $(self.library-name) && ! $(self.include-path) && ! $(self.library-path)
+ {
+ use-environment = true ;
+ }
+ local libnames = $(self.library-name) ;
+ if ! $(libnames) && $(use-environment)
+ {
+ libnames = [ modules.peek : $(name:U)_NAME ] ;
+ # Backward compatibility only.
+ libnames ?= [ modules.peek : $(name:U)_BINARY ] ;
+ }
+ libnames ?= $(self.default-names) ;
+
+ local include-path = $(self.include-path) ;
+ if ! $(include-path) && $(use-environment)
+ {
+ include-path = [ modules.peek : $(name:U)_INCLUDE ] ;
+ }
+
+ local library-path = $(self.library-path) ;
+ if ! $(library-path) && $(use-environment)
+ {
+ library-path = [ modules.peek : $(name:U)_LIBRARY_PATH ] ;
+ # Backwards compatibility only
+ library-path ?= [ modules.peek : $(name:U)_LIBPATH ] ;
+ }
+
+ local toolset = [ $(property-set).get <toolset> ] ;
+ local toolset-version-property = "<toolset-$(toolset):version>" ;
+ local relevant = [ property.select <target-os> <toolset>
+ $(toolset-version-property) <link> <address-model> <architecture> :
+ [ $(property-set).raw ] ] ;
+
+ local key = ac-library-$(name)-$(relevant:J=-) ;
+ local lookup = [ config-cache.get $(key) ] ;
+
+ if $(lookup)
+ {
+ if $(lookup) = missing
+ {
+ configure.log-library-search-result $(name) : "no (cached)" ;
+ return [ property-set.empty ] ;
+ }
+ else
+ {
+ local includes = $(lookup[1]) ;
+ if $(includes) = %default
+ {
+ includes = ;
+ }
+ local library = [ ac.construct-library $(lookup[2]) :
+ [ $(property-set).refine [ property-set.create $(lookup[3]) ] ] : $(library-path) ] ;
+ configure.log-library-search-result $(name) : "yes (cached)" ;
+ return [ $(library[1]).add-raw <include>$(includes) ] $(library[2-]) ;
+ }
+ }
+ else
             {
- # FIXME: this naming is inconsistent with XXX_INCLUDE/XXX_LIBRARY
- if ! ( $($(i)[1]) in root include-path library-path library-name condition )
+ local includes = [ ac.find-include-path $(property-set) : $(self.header) : $(include-path) ] ;
+ local library = [ ac.find-library $(property-set) : $(libnames) : $(library-path) ] ;
+ if $(includes) && $(library)
                 {
- errors.user-error "Invalid named parameter" $($(i)[1]) ;
- }
- local name = $($(i)[1]) ;
- local value = $($(i)[2-]) ;
- if $($(name)) && $($(name)) != $(value)
+ config-cache.set $(key) : $(includes) $(library) ;
+ if $(includes) = %default
+ {
+ includes = ;
+ }
+ library = [ ac.construct-library $(library[1]) :
+ [ $(property-set).refine [ property-set.create $(library[2]) ] ] : $(library-path) ] ;
+ configure.log-library-search-result $(name) : "yes" ;
+ return [ $(library[1]).add-raw <include>$(includes) ] $(library[2-]) ;
+ }
+ else
                 {
- errors.user-error "Attempt to change value of '$(name)'" ;
+ config-cache.set $(key) : missing ;
+ configure.log-library-search-result $(name) : "no" ;
+ return [ property-set.empty ] ;
                 }
- $(name) = $(value) ;
             }
-
- include-path ?= $(root)/include ;
- library-path ?= $(root)/lib ;
- }
+ }
     }
-
- rule construct ( name : sources * : property-set )
+}
+
+class check-library-worker
+{
+ import property-set ;
+ import targets ;
+ import property ;
+
+ rule __init__ ( target : true-properties * : false-properties * )
     {
- # FIXME: log results.
- local libnames = $(library-name) ;
- if ! $(libnames) && ! $(include-path) && ! $(library-path)
- {
- libnames = [ modules.peek : $(name:U)_NAME ] ;
- # Backward compatibility only.
- libnames ?= [ modules.peek : $(name:U)_BINARY ] ;
- }
- libnames ?= $(self.default-names) ;
-
- local includes = [
- ac.find-include-path $(name:U)_INCLUDE : $(property-set) : $(self.header) : $(include-path) ] ;
- local library = [ ac.find-library $(name:U)_LIBRARY : $(property-set) : $(libnames) : $(library-path) ] ;
- if $(includes) && $(library)
- {
- library = [ virtual-target.from-file $(library) : . : $(self.project) ] ;
- configure.log-library-search-result $(name) : "found" ;
- return [ property-set.create <include>$(includes) <source>$(library) ] ;
+ self.target = $(target) ;
+ self.true-properties = $(true-properties) ;
+ self.false-properties = $(false-properties) ;
+ }
+
+ rule check ( properties * )
+ {
+ local choosen ;
+ local t = [ targets.current ] ;
+ local p = [ $(t).project ] ;
+ local ps = [ property-set.create $(properties) ] ;
+ ps = [ $(ps).propagated ] ;
+ local generated =
+ [ targets.generate-from-reference $(self.target) : $(p) : $(ps) ] ;
+ if $(generated[2])
+ {
+ choosen = $(self.true-properties) ;
         }
         else
         {
- configure.log-library-search-result $(name) : "no found" ;
- }
+ choosen = $(self.false-properties) ;
+ }
+ return [ property.evaluate-conditionals-in-context $(choosen) :
+ $(properties) ] ;
     }
 }
 
+rule check-library ( target : true-properties * : false-properties * )
+{
+ local instance = [ class.new check-library-worker $(target) :
+ $(true-properties) : $(false-properties) ] ;
+ return <conditional>@$(instance).check ;
+}

Modified: branches/release/tools/build/v2/build/alias.jam
==============================================================================
--- branches/release/tools/build/v2/build/alias.jam (original)
+++ branches/release/tools/build/v2/build/alias.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,6 +1,7 @@
 # Copyright 2003, 2004, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # This module defines the 'alias' rule and the associated target class.
 #

Modified: branches/release/tools/build/v2/build/build-request.jam
==============================================================================
--- branches/release/tools/build/v2/build/build-request.jam (original)
+++ branches/release/tools/build/v2/build/build-request.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -142,7 +142,7 @@
         {
             skip-next = ;
         }
- else if ! [ MATCH "^(-).*" : $(e) ]
+ else if ! [ MATCH ^(-) : $(e) ]
         {
             # Build request spec either has "=" in it or completely consists of
             # implicit feature values.
@@ -153,7 +153,7 @@
                 properties += [ convert-command-line-element $(e) :
                     $(feature-space) ] ;
             }
- else
+ else if $(e)
             {
                 targets += $(e) ;
             }
@@ -193,8 +193,8 @@
         {
             lresult = [ regex.split $(p) "," ] ;
         }
-
- if $(feature) && free in [ feature.attributes $(feature) ]
+
+ if $(feature) && free in [ feature.attributes <$(feature)> ]
         {
             # If we have free feature, then the value is everything
             # until the end of the command line token. Slashes in
@@ -206,7 +206,7 @@
             lresult = <$(feature)>$(values) ;
             parts = ;
         }
-
+
         if ! [ MATCH (.*-.*) : $(p) ]
         {
             # property.validate cannot handle subfeatures, so we avoid the check
@@ -225,7 +225,7 @@
         {
             result = $(result)/$(lresult) ;
         }
-
+
         parts = $(parts[2-]) ;
     }
 
@@ -294,7 +294,7 @@
     {
         build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ;
     }
- catch \"static\" is not a value of an implicit feature ;
+ catch \"static\" is not an implicit feature value ;
 
     r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ;
     assert.equal [ $(r).get-at 1 ] : target ;

Modified: branches/release/tools/build/v2/build/build_request.py
==============================================================================
--- branches/release/tools/build/v2/build/build_request.py (original)
+++ branches/release/tools/build/v2/build/build_request.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -109,12 +109,12 @@
     properties = []
 
     for e in command_line:
- if e[0] != "-":
+ if e[:1] != "-":
             # Build request spec either has "=" in it, or completely
             # consists of implicit feature values.
             if e.find("=") != -1 or looks_like_implicit_value(e.split("/")[0]):
                 properties += convert_command_line_element(e)
- else:
+ elif e:
                 targets.append(e)
 
     return [targets, properties]

Modified: branches/release/tools/build/v2/build/configure.jam
==============================================================================
--- branches/release/tools/build/v2/build/configure.jam (original)
+++ branches/release/tools/build/v2/build/configure.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,25 +6,24 @@
 
 # This module defines function to help with two main tasks:
 #
-# - Discovering build-time configuration for the purposes of adjusting
-# build process.
+# - Discovering build-time configuration for the purposes of adjusting the build
+# process.
 # - Reporting what is built, and how it is configured.
 
-import targets ;
-import errors ;
-import targets ;
-import sequence ;
-import property ;
-import property-set ;
 import "class" : new ;
 import common ;
 import path ;
+import property ;
+import property-set ;
+import targets ;
+import config-cache ;
+
 
 rule log-summary ( )
 {
-
 }
 
+
 .width = 30 ;
 
 rule set-width ( width )
@@ -32,29 +31,33 @@
     .width = $(width) ;
 }
 
+
 # Declare that the components specified by the parameter exist.
+#
 rule register-components ( components * )
 {
     .components += $(components) ;
 }
 
-# Declare that the components specified by the parameters will
-# be build.
+
+# Declare that the components specified by the parameters will be built.
+#
 rule components-building ( components * )
 {
     .built-components += $(components) ;
 }
 
-# Report something about component configuration that the
-# user should better know.
+
+# Report something about component configuration that the user should better
+# know.
+#
 rule log-component-configuration ( component : message )
 {
- # FIXME: implement per-property-set logs
+ # FIXME: Implement per-property-set logs.
     .component-logs.$(component) += $(message) ;
 }
 
 
-
 rule log-check-result ( result )
 {
     if ! $(.announced-checks)
@@ -62,22 +65,27 @@
         ECHO "Performing configuration checks\n" ;
         .announced-checks = 1 ;
     }
-
- ECHO $(result) ;
+
+ ECHO $(result) ;
+ # FIXME: Unfinished code. Nothing seems to set .check-results at the moment.
     #.check-results += $(result) ;
 }
 
+
 rule log-library-search-result ( library : result )
 {
- local x = [ PAD " - $(library) : $(result)" : $(.width) ] ;
- log-check-result "$(x)" ;
+ local x = [ PAD " - $(library)" : $(.width) ] ;
+ log-check-result "$(x) : $(result)" ;
 }
 
+
 rule print-component-configuration ( )
 {
- local c = [ sequence.unique $(.components) ] ;
-
+ # FIXME: See what was intended with this initial assignment.
+ # local c = [ sequence.unique $(.components) ] ;
+
     ECHO "\nComponent configuration:\n" ;
+ local c ;
     for c in $(.components)
     {
         local s ;
@@ -93,70 +101,99 @@
         for local m in $(.component-logs.$(c))
         {
             ECHO " -" $(m) ;
- }
+ }
     }
     ECHO ;
 }
 
+
 rule print-configure-checks-summary ( )
 {
- # FIXME: the problem with that approach is tha
- # the user sees checks summary when all checks are
- # done, and has no progress reporting while the
- # checks are being executed.
+ # FIXME: The problem with this approach is that the user sees the checks
+ # summary when all checks are done, and has no progress reporting while the
+ # checks are being executed.
     if $(.check-results)
- {
+ {
         ECHO "Configuration checks summary\n" ;
-
         for local r in $(.check-results)
         {
             ECHO $(r) ;
         }
         ECHO ;
- }
+ }
 }
 
-# Attempt to build a metatarget named by 'metatarget-reference'
-# in context of 'project' with properties 'ps'.
-# Returns non-empty value if build is OK.
+
+# Attempt to build a metatarget named by 'metatarget-reference' in context of
+# 'project' with properties 'ps'. Returns non-empty value if build is OK.
+#
 rule builds-raw ( metatarget-reference : project : ps : what : retry ? )
-{
+{
     local result ;
-
+
     if ! $(retry) && ! $(.$(what)-tested.$(ps))
- {
+ {
         .$(what)-tested.$(ps) = true ;
+
+ local cache-name = $(what) [ $(ps).raw ] ;
+ cache-name = $(cache-name:J=-) ;
+ local value = [ config-cache.get $(cache-name) ] ;
         
         local targets = [ targets.generate-from-reference
             $(metatarget-reference) : $(project) : $(ps) ] ;
-
+
         local jam-targets ;
         for local t in $(targets[2-])
         {
             jam-targets += [ $(t).actualize ] ;
         }
-
- if ! UPDATE_NOW in [ RULENAMES ]
+
+ if $(value)
+ {
+ local x = [ PAD " - $(what)" : $(.width) ] ;
+ if $(value) = true
+ {
+ .$(what)-supported.$(ps) = yes ;
+ result = true ;
+ log-check-result "$(x) : yes (cached)" ;
+ }
+ else
+ {
+ log-check-result "$(x) : no (cached)" ;
+ }
+ }
+ else if ! UPDATE_NOW in [ RULENAMES ]
         {
             # Cannot determine. Assume existance.
         }
- else
- {
- local x = [ PAD " - $(what)" : $(.width) ] ;
+ else
+ {
+ local x = [ PAD " - $(what)" : $(.width) ] ;
             if [ UPDATE_NOW $(jam-targets) :
- $(.log-fd) : ignore-minus-n : ignore-minus-q ]
+ $(.log-fd) : ignore-minus-n : ignore-minus-q ]
             {
                 .$(what)-supported.$(ps) = yes ;
                 result = true ;
                 log-check-result "$(x) : yes" ;
- }
+ }
             else
             {
                 log-check-result "$(x) : no" ;
             }
+ }
+ if ! $(value)
+ {
+ if $(result)
+ {
+ config-cache.set $(cache-name) : true ;
+ }
+ else
+ {
+ config-cache.set $(cache-name) : false ;
+ }
         }
         return $(result) ;
- }
+ }
     else
     {
         return $(.$(what)-supported.$(ps)) ;
@@ -165,33 +202,39 @@
 
 rule builds ( metatarget-reference : properties * : what ? : retry ? )
 {
- what ?= "$(metatarget-reference) builds" ;
-
- # FIXME: this should not be hardcoded. Other checks might
- # want to consider different set of features as relevant.
+ # FIXME: This should not be hardcoded. Other checks might want to consider a
+ # different set of features as relevant.
     local toolset = [ property.select <toolset> : $(properties) ] ;
     local toolset-version-property = "<toolset-$(toolset:G=):version>" ;
- local relevant = [ property.select <target-os> <toolset> $(toolset-version-property)
- <address-model> <architecture>
- : $(properties) ] ;
- local ps = [ property-set.create $(relevant) ] ;
+ local relevant = [ property.select <target-os> <toolset>
+ $(toolset-version-property) <address-model> <architecture> :
+ $(properties) ] ;
+ local ps = [ property-set.create $(relevant) ] ;
     local t = [ targets.current ] ;
     local p = [ $(t).project ] ;
 
- return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) : $(retry) ] ;
+ if ! $(what)
+ {
+ local resolved = [ targets.resolve-reference $(metatarget-reference) : $(p) ] ;
+ local name = [ $(resolved[1]).name ] ;
+ what = "$(name) builds" ;
+ }
+
+ return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) :
+ $(retry) ] ;
 }
 
 
-# Called by Boost.Build startup code to specify name of a file
-# that will receive results of configure checks. This
-# should never be called by users.
+# Called by Boost.Build startup code to specify the file to receive the
+# configuration check results. Should never be called by user code.
+#
 rule set-log-file ( log-file )
 {
     path.makedirs [ path.parent $(log-file) ] ;
-
     .log-fd = [ FILE_OPEN $(log-file) : "w" ] ;
 }
 
+
 # Frontend rules
 
 class check-target-builds-worker
@@ -199,39 +242,40 @@
     import configure ;
     import property-set ;
     import targets ;
- import property ;
-
- rule __init__ ( target message ? : true-properties * : false-properties * )
+ import property ;
+
+ rule __init__ ( target message ? : true-properties * : false-properties * )
     {
         self.target = $(target) ;
- self.message = $(message) ;
+ self.message = $(message) ;
         self.true-properties = $(true-properties) ;
         self.false-properties = $(false-properties) ;
     }
-
+
     rule check ( properties * )
     {
         local choosen ;
         if [ configure.builds $(self.target) : $(properties) : $(self.message) ]
         {
             choosen = $(self.true-properties) ;
- }
+ }
         else
         {
             choosen = $(self.false-properties) ;
- }
- return [ property.evaluate-conditionals-in-context $(choosen) : $(properties) ] ;
- }
+ }
+ return [ property.evaluate-conditionals-in-context $(choosen) :
+ $(properties) ] ;
+ }
 }
 
 
-rule check-target-builds ( target message ? : true-properties * : false-properties * )
+rule check-target-builds ( target message ? : true-properties * :
+ false-properties * )
 {
- local instance = [ new check-target-builds-worker $(target) $(message) : $(true-properties)
- : $(false-properties) ] ;
+ local instance = [ new check-target-builds-worker $(target) $(message) :
+ $(true-properties) : $(false-properties) ] ;
     return <conditional>@$(instance).check ;
 }
 
-IMPORT $(__name__) : check-target-builds : : check-target-builds ;
-
 
+IMPORT $(__name__) : check-target-builds : : check-target-builds ;

Modified: branches/release/tools/build/v2/build/feature.jam
==============================================================================
--- branches/release/tools/build/v2/build/feature.jam (original)
+++ branches/release/tools/build/v2/build/feature.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,11 +2,11 @@
 # Copyright 2002, 2006 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import assert : * ;
 import "class" : * ;
-import errors : lol->list ;
 import indirect ;
 import modules ;
 import regex ;
@@ -133,9 +133,10 @@
 
     if $(error)
     {
+ import errors ;
         errors.error $(error)
               : "in" feature declaration:
- : feature [ lol->list $(1) : $(2) : $(3) ] ;
+ : feature [ errors.lol->list $(1) : $(2) : $(3) ] ;
     }
 
     $(name).values ?= ;
@@ -173,12 +174,14 @@
     }
     if $(bad-attribute)
     {
- errors.error "$(bad-attribute) property $(f) cannot have a default." ;
+ import errors ;
+ errors.error $(bad-attribute) property $(f) cannot have a default. ;
     }
     if ! $(value) in $($(f).values)
     {
- errors.error "The specified default value, '$(value)' is invalid"
- : "allowed values are: " $($(f).values) ;
+ import errors ;
+ errors.error The specified default value, '$(value)' is invalid :
+ allowed values are: $($(f).values) ;
     }
     $(f).default = $(value) ;
 }
@@ -220,7 +223,7 @@
 #
 rule attributes ( feature )
 {
- return $($(:E=:G=$(feature)).attributes) ;
+ return $($(feature).attributes) ;
 }
 
 
@@ -266,11 +269,11 @@
 rule implied-feature ( implicit-value )
 {
     local components = [ regex.split $(implicit-value) "-" ] ;
-
     local feature = $($(components[1]).implicit-feature) ;
     if ! $(feature)
     {
- errors.error \"$(implicit-value)\" is not a value of an implicit feature ;
+ import errors ;
+ errors.error \"$(implicit-value)\" is not an implicit feature value ;
         feature = "" ; # Keep testing happy; it expects a result.
     }
     return $(feature) ;
@@ -282,9 +285,9 @@
     # Feature should be of the form <feature-name>.
     if $(feature) != $(feature:G)
     {
+ import errors ;
         errors.error invalid feature $(feature) ;
     }
-
     return $($(feature)$(value-string:E="")<>$(subvalue).subfeature) ;
 }
 
@@ -304,6 +307,7 @@
     if ! $(subfeature)
     {
         value-string ?= "" ;
+ import errors ;
         errors.error \"$(subvalue)\" is not a known subfeature value of
             $(feature)$(value-string) ;
     }
@@ -317,6 +321,7 @@
 {
     if ! $(feature) in $(.all-features)
     {
+ import errors ;
         errors.error unknown feature \"$(feature)\" ;
     }
 }
@@ -439,7 +444,9 @@
         {
             if $($(v).implicit-feature)
             {
- errors.error $(v) is already associated with the \"$($(v).implicit-feature)\" feature ;
+ import errors ;
+ errors.error $(v) is already associated with the
+ \"$($(v).implicit-feature)\" feature ;
             }
             $(v).implicit-feature = $(feature) ;
         }
@@ -469,8 +476,8 @@
 
         if $($(feature).subfeatures)
         {
- if ! ( $(value-string) in $($(feature).values) )
- && ! ( $(value-string) in $($(feature).subfeatures) )
+ if ! $(value-string) in $($(feature).values)
+ $($(feature).subfeatures)
             {
                 values = [ regex.split $(value-string) - ] ;
             }
@@ -481,8 +488,9 @@
             # An empty value is allowed for optional features.
             ( $(values[1]) || ! ( optional in $($(feature).attributes) ) )
         {
- errors.error \"$(values[1])\" is not a known value of feature $(feature)
- : legal values: \"$($(feature).values)\" ;
+ import errors ;
+ errors.error \"$(values[1])\" is not a known value of feature
+ $(feature) : legal values: \"$($(feature).values)\" ;
         }
 
         for local v in $(values[2-])
@@ -607,12 +615,12 @@
         # value-string.
         if $(value-string)
         {
+ import errors ;
             errors.error can only specify a property as the first argument when
                 extending a subfeature
                 : usage:
                 : " extend" feature ":" values...
- : " | extend" <feature>value-string subfeature ":" values...
- ;
+ : " | extend" <feature>value-string subfeature ":" values... ;
         }
 
         extend-feature $(feature) : $(values) ;
@@ -646,8 +654,9 @@
 
     if $(subfeature-name) in $($(feature).subfeatures)
     {
- errors.error \"$(subfeature)\" already declared as a subfeature of \"$(feature)\"
- "specific to "$(value-string) ;
+ import errors ;
+ errors.error \"$(subfeature)\" already declared as a subfeature of
+ \"$(feature)\" "specific to "$(value-string) ;
     }
     $(feature).subfeatures += $(subfeature-name) ;
 
@@ -667,18 +676,21 @@
     local feature = $(composite-property:G) ;
     if ! ( composite in [ attributes $(feature) ] )
     {
+ import errors ;
         errors.error "$(feature)" is not a composite feature ;
     }
 
     $(composite-property).components ?= ;
     if $($(composite-property).components)
     {
+ import errors ;
         errors.error components of "$(composite-property)" already set:
             $($(composite-property).components) ;
     }
 
     if $(composite-property) in $(component-properties)
     {
+ import errors ;
         errors.error composite property "$(composite-property)" cannot have itself as a component ;
     }
     $(composite-property).components = $(component-properties) ;
@@ -748,6 +760,7 @@
                     {
                         if $(f) in $(result:G)
                         {
+ import errors ;
                             errors.error expansions of composite features result
                                 in conflicting values for $(f)
                                 : values: [ get-values $(f) : $(result) ] $(x:G=)
@@ -761,6 +774,7 @@
                 }
                 else if $(f) in $(result:G)
                 {
+ import errors ;
                     errors.error explicitly-specified values of non-free feature
                         $(f) conflict :
                         "existing values:" [ get-values $(f) : $(properties) ] :
@@ -900,6 +914,7 @@
     local implicits = [ set.intersection $(p:G=) : $(p:G) ] ;
     if $(implicits)
     {
+ import errors ;
         errors.error minimize requires an expanded property set, but
             \"$(implicits[1])\" appears to be the value of an un-expanded
             implicit feature ;
@@ -1048,6 +1063,7 @@
     {
         if $(v) in $(properties)
         {
+ import errors ;
             errors.error add-defaults requires explicitly specified features,
                 but \"$(v)\" appears to be the value of an un-expanded implicit
                 feature ;
@@ -1216,7 +1232,6 @@
     subfeature fu : subfu2 : q r s ;
 
     assert.result optional : attributes <fu> ;
- assert.result optional : attributes fu ;
 
     assert.result <runtime-link>static <define>foobar <optimization>on
         <toolset>gcc:<define>FOO <toolset>gcc <variant>debug <stdlib>native
@@ -1316,7 +1331,7 @@
     {
         implied-feature lackluster ;
     }
- catch \"lackluster\" is not a value of an implicit feature ;
+ catch \"lackluster\" is not an implicit feature value ;
 
     try ;
     {

Modified: branches/release/tools/build/v2/build/generators.jam
==============================================================================
--- branches/release/tools/build/v2/build/generators.jam (original)
+++ branches/release/tools/build/v2/build/generators.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,9 +1,9 @@
-# Copyright Vladimir Prus 2002.
-# Copyright Rene Rivera 2006.
+# Copyright 2002. Vladimir Prus
+# Copyright 2006. Rene Rivera
 #
 # 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 accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Manages 'generators' --- objects which can do transformation between different
 # target types and contain algorithm for finding transformation from sources to
@@ -44,7 +44,6 @@
 # converting between given target types.
 
 import "class" : new ;
-import errors ;
 import property-set ;
 import sequence ;
 import set ;
@@ -162,17 +161,16 @@
 #
 class generator
 {
+ import "class" : new ;
+ import feature ;
     import generators : indent increase-indent decrease-indent generators.dout ;
- import set ;
     import utility ;
- import feature ;
- import errors ;
+ import path ;
+ import property ;
     import sequence ;
+ import set ;
     import type ;
     import virtual-target ;
- import "class" : new ;
- import property ;
- import path ;
 
     EXPORT class_at_generator : indent increase-indent decrease-indent
         generators.dout ;
@@ -222,6 +220,18 @@
             self.name-prefix += $(m[3]:E="") ;
             self.name-postfix += $(m[4]:E="") ;
         }
+
+ for local r in [ requirements ]
+ {
+ if $(r:G=)
+ {
+ self.property-requirements += $(r) ;
+ }
+ else
+ {
+ self.feature-requirements += $(r) ;
+ }
+ }
 
         # Note that 'transform' here, is the same as 'for_each'.
         sequence.transform type.validate : $(self.source-types) ;
@@ -262,17 +272,17 @@
     {
         return $(self.requirements) ;
     }
-
+
     rule set-rule-name ( rule-name )
     {
         self.rule-name = $(rule-name) ;
     }
-
+
     rule rule-name ( )
     {
         return $(self.rule-name) ;
     }
-
+
     # Returns a true value if the generator can be run with the specified
     # properties.
     #
@@ -281,24 +291,9 @@
         # See if generator requirements are satisfied by 'properties'. Treat a
         # feature name in requirements (i.e. grist-only element), as matching
         # any value of the feature.
- local all-requirements = [ requirements ] ;
-
- local property-requirements feature-requirements ;
- for local r in $(all-requirements)
- {
- if $(r:G=)
- {
- property-requirements += $(r) ;
- }
- else
- {
- feature-requirements += $(r) ;
- }
- }
 
- local properties-to-match = [ $(property-set-to-match).raw ] ;
- if $(property-requirements) in $(properties-to-match) &&
- $(feature-requirements) in $(properties-to-match:G)
+ if [ $(property-set-to-match).contains-raw $(self.property-requirements) ] &&
+ [ $(property-set-to-match).contains-features $(self.feature-requirements) ]
         {
             return true ;
         }
@@ -319,7 +314,7 @@
             # Note: this does not remove any subfeatures of <toolset> which
             # might cause problems.
             [ property.change $(self.requirements) : <toolset> ]
- $(new-toolset-properties) ] ;
+ $(new-toolset-properties) ] ;
         return $(g) ;
     }
 
@@ -346,10 +341,10 @@
         local g = [ new $(__class__) $(self.id) $(self.composing) :
             $(self.source-types) : $(target-types) : $(self.requirements) ] ;
         if $(self.rule-name)
- {
+ {
             $(g).set-rule-name $(self.rule-name) ;
- }
- return $(g) ;
+ }
+ return $(g) ;
     }
 
     # Tries to invoke this generator on the given sources. Returns a list of
@@ -372,6 +367,7 @@
 
         if ! $(self.composing) && $(sources[2]) && $(self.source-types[2])
         {
+ import errors : error : errors.error ;
             errors.error "Unsupported source/source-type combination" ;
         }
 
@@ -447,7 +443,7 @@
     )
     {
         local result ;
- # If this is 1->1 transformation, apply it to all consumed targets in
+ # If this is a 1->1 transformation, apply it to all consumed targets in
         # order.
         if ! $(self.source-types[2]) && ! $(self.composing)
         {
@@ -471,23 +467,22 @@
     rule determine-target-name ( fullname : prefix ? : postfix ? )
     {
         # See if we need to add directory to the target name.
- local dir = $(fullname:D) ;
- local name = $(fullname:B) ;
-
+ local dir = $(fullname:D) ;
+ local name = $(fullname:B) ;
+
         name = $(prefix:E=)$(name) ;
         name = $(name)$(postfix:E=) ;
 
- if $(dir) &&
- # Never append '..' to target path.
- ! [ MATCH .*(\\.\\.).* : $(dir) ]
- &&
- ! [ path.is-rooted $(dir) ]
- {
- # Relative path is always relative to the source
- # directory. Retain it, so that users can have files
- # with the same in two different subdirectories.
- name = $(dir)/$(name) ;
- }
+ if $(dir)
+ # Never append '..' to target path.
+ && ! [ MATCH .*(\\.\\.).* : $(dir) ]
+ && ! [ path.is-rooted $(dir) ]
+ {
+ # Relative path is always relative to the source directory. Retain
+ # it, so that users can have files with the same name in two
+ # different subdirectories.
+ name = $(dir)/$(name) ;
+ }
         return $(name) ;
     }
 
@@ -504,17 +499,15 @@
         # second case -- not sure, but for now take the part up to the last dot
         # too.
         name = [ utility.basename [ $(sources[1]).name ] ] ;
-
- for local s in $(sources[2])
+ for local s in $(sources[2-])
         {
- local n2 = [ utility.basename [ $(s).name ] ] ;
- if $(n2) != $(name)
+ if [ utility.basename [ $(s).name ] ] != $(name)
             {
+ import errors : error : errors.error ;
                 errors.error "$(self.id): source targets have different names: cannot determine target name" ;
             }
         }
- name = [ determine-target-name [ $(sources[1]).name ] ] ;
- return $(name) ;
+ return [ determine-target-name [ $(sources[1]).name ] ] ;
     }
 
     # Constructs targets that are created after consuming 'sources'. The result
@@ -524,10 +517,10 @@
     # When 'name' is empty, all source targets must have the same 'name'
     # attribute value, which will be used instead of the 'name' argument.
     #
- # The 'name' attribute value for each generated target will be equal to
- # the 'name' parameter if there is no name pattern for this type. Otherwise,
- # the '%' symbol in the name pattern will be replaced with the 'name'
- # parameter to obtain the 'name' attribute.
+ # The 'name' attribute value for each generated target will be equal to the
+ # 'name' parameter if there is no name pattern for this type. Otherwise, the
+ # '%' symbol in the name pattern will be replaced with the 'name' parameter
+ # to obtain the 'name' attribute.
     #
     # For example, if targets types are T1 and T2 (with name pattern "%_x"),
     # suffixes for T1 and T2 are .t1 and .t2, and source is foo.z, then created
@@ -607,7 +600,7 @@
             missing-types = ;
         }
 
- # TODO: we should check that only one source type if create of
+ # TODO: we should check that only one source type is created if
         # 'only-one' is true.
 
         if $(missing-types)
@@ -642,17 +635,40 @@
         local result ;
         # We process each source one-by-one, trying to convert it to a usable
         # type.
- for local source in $(sources)
+ if ! $(self.source-types)
         {
- local _c = [ convert-to-consumable-types $(project) : $(property-set)
- : $(source) : true ] ;
- if ! $(_c)
+ # Anything is acceptible
+ return $(sources) ;
+ }
+ else
+ {
+ local acceptible-types = [ sequence.unique
+ [ sequence.transform type.all-derived : $(self.source-types) ] ] ;
+ for local source in $(sources)
             {
- generators.dout [ indent ] " failed to convert " $(source) ;
+ if ! [ $(source).type ] in $(acceptible-types)
+ {
+ local transformed = [ generators.construct-types $(project)
+ : $(self.source-types) : $(property-set) : $(source) ] ;
+ for local t in $(transformed[2-])
+ {
+ if [ $(t).type ] in $(self.source-types)
+ {
+ result += $(t) ;
+ }
+ }
+ if ! $(transformed)
+ {
+ generators.dout [ indent ] " failed to convert " $(source) ;
+ }
+ }
+ else
+ {
+ result += $(source) ;
+ }
             }
- result += $(_c) ;
+ return [ sequence.unique $(result) ] ;
         }
- return $(result) ;
     }
 
     rule consume-directly ( source )
@@ -697,7 +713,7 @@
 rule register ( g )
 {
     .all-generators += $(g) ;
-
+
     # A generator can produce several targets of the same type. We want unique
     # occurrence of that generator in .generators.$(t) in that case, otherwise,
     # it will be tried twice and we will get a false ambiguity.
@@ -1082,6 +1098,7 @@
     {
         if ! [ $(t).type ]
         {
+ import errors ;
             errors.error "target" [ $(t).str ] "has no type" ;
         }
     }
@@ -1103,27 +1120,42 @@
 {
     # Select generators that can create the required target type.
     local viable-generators = ;
- local generator-rank = ;
 
     import type ;
- local t = [ type.all-bases $(target-type) ] ;
+ local t = $(target-type) ;
 
- generators.dout [ indent ] find-viable-generators target-type= $(target-type)
- property-set= [ $(property-set).as-path ] ;
+ if $(.debug)
+ {
+ generators.dout [ indent ] find-viable-generators target-type= $(target-type)
+ property-set= [ $(property-set).as-path ] ;
+ generators.dout [ indent ] "trying type" $(target-type) ;
+ }
 
- # Get the list of generators for the requested type. If no generator is
- # registered, try base type, and so on.
- local generators ;
- while $(t[1])
+ local generators = $(.generators.$(target-type)) ;
+ if $(generators)
     {
- generators.dout [ indent ] "trying type" $(t[1]) ;
- if $(.generators.$(t[1]))
+ if $(.debug)
         {
             generators.dout [ indent ] "there are generators for this type" ;
- generators = $(.generators.$(t[1])) ;
+ }
+ }
+ else
+ {
+ local t = [ type.base $(target-type) ] ;
 
- if $(t[1]) != $(target-type)
+ # Get the list of generators for the requested type. If no generator is
+ # registered, try base type, and so on.
+ while $(t)
+ {
+ if $(.debug)
+ {
+ generators.dout [ indent ] "trying type" $(t) ;
+ }
+ if $(.generators.$(t))
             {
+ generators.dout [ indent ] "there are generators for this type" ;
+ generators = $(.generators.$(t)) ;
+
                 # We are here because there were no generators found for
                 # target-type but there are some generators for its base type.
                 # We will try to use them, but they will produce targets of
@@ -1137,25 +1169,33 @@
                     # should work. That list is only used when inheriting a
                     # toolset, which should have been done before running
                     # generators.
- generators2 += [ $(g).clone-and-change-target-type $(t[1]) :
+ generators2 += [ $(g).clone-and-change-target-type $(t) :
                         $(target-type) ] ;
                     generators.register $(generators2[-1]) ;
                 }
                 generators = $(generators2) ;
+ t = ;
+ }
+ else
+ {
+ t = [ type.base $(t) ] ;
             }
- t = ;
         }
- t = $(t[2-]) ;
     }
 
     for local g in $(generators)
     {
- generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
+ if $(.debug)
+ {
+ generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
+ }
 
- local m = [ $(g).match-rank $(property-set) ] ;
- if $(m)
+ if [ $(g).match-rank $(property-set) ]
         {
- generators.dout [ indent ] " is viable" ;
+ if $(.debug)
+ {
+ generators.dout [ indent ] " is viable" ;
+ }
             viable-generators += $(g) ;
         }
     }
@@ -1194,7 +1234,7 @@
         else
         {
             generators.dout [ indent ] " generator " [ $(g).id ] "is active, discaring" ;
- }
+ }
     }
 
     # Generators which override 'all'.
@@ -1313,7 +1353,7 @@
         saved-active = $(.active-generators) ;
         .active-generators = ;
     }
-
+
     if (.construct-stack)
     {
         ensure-type $(sources) ;
@@ -1340,7 +1380,7 @@
     decrease-indent ;
 
     .construct-stack = $(.construct-stack[2-]) ;
-
+
     if $(top-level)
     {
         .active-generators = $(saved-active) ;
@@ -1374,7 +1414,7 @@
 {
     for local g in $(.all-generators)
     {
- ECHO [ $(g).id ] ":" [ $(g).source-types ] -> [ $(g).target-types ] ;
- }
+ ECHO [ $(g).id ] ":" [ $(g).source-types ] -> [ $(g).target-types ] ;
+ }
 }
 

Deleted: branches/release/tools/build/v2/build/modifiers.jam
==============================================================================
--- branches/release/tools/build/v2/build/modifiers.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
+++ (empty file)
@@ -1,232 +0,0 @@
-# Copyright 2003 Rene Rivera
-# 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)
-
-# Modifiers are generalized generators that mutate targets in specific ways.
-# This structure allows for grouping a variety of functionality in an
-# orthogonal way to the functionality in toolsets, and without specifying
-# more target variations. In turn the modifiers can be used as building
-# blocks to implement simple requests, like the <version> feature.
-
-import modules ;
-import feature ;
-import errors ;
-import type ;
-import "class" : new ;
-import generators ;
-import property ;
-import virtual-target ;
-import numbers ;
-import sequence ;
-import symlink ;
-import property-set ;
-
-# Base generator for creating targets that are modifications of existing
-# targets.
-#
-class modifier : generator
-{
- rule __init__ (
- id
- composing ?
- : source-types *
- : target-types-and-names +
- : requirements *
- )
- {
- generator.__init__ $(id) $(composing)
- : $(source-types)
- : $(target-types-and-names)
- : $(requirements) ;
-
- self.targets-in-progress = ;
- }
-
- # Wraps the generation of the target to call before and after rules to
- # affect the real target.
- #
- rule run ( project name ? : property-set : sources + )
- {
- local result ;
- local current-target = $(project)^$(name) ;
- if ! $(current-target) in $(self.targets-in-progress)
- {
- # Before modifications...
- local project_ =
- [ modify-project-before
- $(project) $(name) : $(property-set) : $(sources) ] ;
- local name_ =
- [ modify-name-before
- $(project) $(name) : $(property-set) : $(sources) ] ;
- local property-set_ =
- [ modify-properties-before
- $(project) $(name) : $(property-set) : $(sources) ] ;
- local sources_ =
- [ modify-sources-before
- $(project) $(name) : $(property-set) : $(sources) ] ;
- project = $(project_) ;
- name = $(name_) ;
- property-set = $(property-set_) ;
- sources = $(sources_) ;
-
- # Generate the real target...
- local target-type-p =
- [ property.select <main-target-type> : [ $(property-set).raw ] ] ;
- self.targets-in-progress += $(current-target) ;
- result =
- [ generators.construct $(project) $(name)
- : $(target-type-p:G=)
- : $(property-set)
- : $(sources) ] ;
- self.targets-in-progress = $(self.targets-in-progress[1--2]) ;
-
- # After modifications...
- result =
- [ modify-target-after $(result)
- : $(project) $(name)
- : $(property-set)
- : $(sources) ] ;
- }
- return $(result) ;
- }
-
- rule modify-project-before ( project name ? : property-set : sources + )
- {
- return $(project) ;
- }
-
- rule modify-name-before ( project name ? : property-set : sources + )
- {
- return $(name) ;
- }
-
- rule modify-properties-before ( project name ? : property-set : sources + )
- {
- return $(property-set) ;
- }
-
- rule modify-sources-before ( project name ? : property-set : sources + )
- {
- return $(sources) ;
- }
-
- rule modify-target-after ( target : project name ? : property-set : sources + )
- {
- return $(target) ;
- }
-
- # Utility, clones a file-target with optional changes to the name, type and
- # project of the target.
- # NOTE: This functionality should be moved, and generalized, to
- # virtual-targets.
- #
- rule clone-file-target ( target : new-name ? : new-type ? : new-project ? )
- {
- # Need a MUTCH better way to clone a target...
- new-name ?= [ $(target).name ] ;
- new-type ?= [ $(target).type ] ;
- new-project ?= [ $(target).project ] ;
- local result = [ new file-target $(new-name) : $(new-type) : $(new-project) ] ;
-
- if [ $(target).dependencies ] { $(result).depends [ $(target).dependencies ] ; }
- $(result).root [ $(target).root ] ;
- $(result).set-usage-requirements [ $(target).usage-requirements ] ;
-
- local action = [ $(target).action ] ;
- local action-class = [ modules.peek $(action) : __class__ ] ;
-
- local ps = [ $(action).properties ] ;
- local cloned-action = [ new $(action-class) $(result) :
- [ $(action).sources ] : [ $(action).action-name ] : $(ps) ] ;
- $(result).action $(cloned-action) ;
-
- return $(result) ;
- }
-}
-
-
-# A modifier that changes the name of a target, after it's generated, given a
-# regular expression to split the name, and a set of token to insert between the
-# split tokens of the name. This also exposes the target for other uses with a
-# symlink to the original name (optionally).
-#
-class name-modifier : modifier
-{
- rule __init__ ( )
- {
- # Apply ourselves to EXE targets, for now.
- modifier.__init__ name.modifier : : EXE LIB : <name-modify>yes ;
- }
-
- # Modifies the name, by cloning the target with the new name.
- #
- rule modify-target-after ( target : project name ? : property-set : sources + )
- {
- local result = $(target) ;
-
- local name-mod-p = [ property.select <name-modifier> : [ $(property-set).raw ] ] ;
- if $(name-mod-p)
- {
- local new-name = [ modify-name [ $(target).name ] : $(name-mod-p:G=) ] ;
- if $(new-name) != [ $(target).name ]
- {
- result = [ clone-file-target $(target) : $(new-name) ] ;
- }
- local expose-original-as-symlink = [ MATCH "<symlink>(.*)" : $(name-mod-p) ] ;
- if $(expose-original-as-symlink)
- {
- local symlink-t = [ new symlink-targets $(project) : $(name) : [ $(result).name ] ] ;
- result = [ $(symlink-t).construct $(result)
- : [ property-set.create [ $(property-set).raw ] <symlink-location>build-relative ] ] ;
- }
- }
-
- return $(result) ;
- }
-
- # Do the transformation of the name.
- #
- rule modify-name ( name : modifier-spec + )
- {
- local match = [ MATCH "<match>(.*)" : $(modifier-spec) ] ;
- local name-parts = [ MATCH $(match) : $(name) ] ;
- local insertions = [ sequence.insertion-sort [ MATCH "(<[0123456789]+>.*)" : $(modifier-spec) ] ] ;
- local new-name-parts ;
- local insert-position = 1 ;
- while $(insertions)
- {
- local insertion = [ MATCH "<$(insert-position)>(.*)" : $(insertions[1]) ] ;
- if $(insertion)
- {
- new-name-parts += $(insertion) ;
- insertions = $(insertions[2-]) ;
- }
- new-name-parts += $(name-parts[1]) ;
- name-parts = $(name-parts[2-]) ;
- insert-position = [ numbers.increment $(insert-position) ] ;
- }
- new-name-parts += $(name-parts) ;
- return [ sequence.join $(new-name-parts) ] ;
- }
-
- rule optional-properties ( )
- {
- return <name-modify>yes ;
- }
-}
-feature.feature name-modifier : : free ;
-feature.feature name-modify : no yes : incidental optional ;
-generators.register [ new name-modifier ] ;
-
-# Translates <version> property to a set of modification properties
-# that are applied by the name-modifier, and symlink-modifier.
-#
-rule version-to-modifier ( property : properties * )
-{
- return
- <name-modify>yes
- <name-modifier><match>"^([^.]*)(.*)" <name-modifier><2>.$(property:G=)
- <name-modifier><symlink>yes
- ;
-}
-feature.action <version> : version-to-modifier ;

Modified: branches/release/tools/build/v2/build/project.jam
==============================================================================
--- branches/release/tools/build/v2/build/project.jam (original)
+++ branches/release/tools/build/v2/build/project.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,40 +2,39 @@
 # Copyright 2002, 2005, 2006 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Implements project representation and loading. Each project is represented by:
-# - a module where all the Jamfile content live.
+# - a module where all the Jamfile content lives.
 # - an instance of 'project-attributes' class.
 # (given a module name, can be obtained using the 'attributes' rule)
 # - an instance of 'project-target' class (from targets.jam)
 # (given a module name, can be obtained using the 'target' rule)
 #
 # Typically, projects are created as result of loading a Jamfile, which is done
-# by rules 'load' and 'initialize', below. First, module for Jamfile is loaded
-# and new project-attributes instance is created. Some rules necessary for
-# project are added to the module (see 'project-rules' module) at the bottom of
-# this file. Default project attributes are set (inheriting attributes of parent
-# project, if it exists). After that the Jamfile is read. It can declare its own
-# attributes using the 'project' rule which will be combined with any already
-# set attributes.
+# by rules 'load' and 'initialize', below. First, a module is prepared and a new
+# project-attributes instance is created. Some rules necessary for all projects
+# are added to the module (see the 'project-rules' module). Default project
+# attributes are set (inheriting parent project attributes, if it exists). After
+# that the Jamfile is read. It can declare its own attributes using the
+# 'project' rule which will be combined with any already set.
 #
 # The 'project' rule can also declare a project id which will be associated with
 # the project module.
 #
-# There can also be 'standalone' projects. They are created by calling
-# 'initialize' on an arbitrary module and not specifying their location. After
-# the call, the module can call the 'project' rule, declare main targets and
-# behave as a regular project except that, since it is not associated with any
-# location, it should not declare targets that are not prebuilt.
+# Besides Jamfile projects, we also support 'standalone' projects created by
+# calling 'initialize' in an arbitrary module and not specifying the project's
+# location. After the call, the module can call the 'project' rule, declare main
+# targets and behave as a regular project except that, since it is not
+# associated with any location, it should only declare prebuilt targets.
 #
-# The list of all loaded Jamfile is stored in the .project-locations variable.
+# The list of all loaded Jamfiles is stored in the .project-locations variable.
 # It is possible to obtain a module name for a location using the 'module-name'
 # rule. Standalone projects are not recorded and can only be referenced using
 # their project id.
 
 import "class" : new ;
-import errors ;
 import modules ;
 import path ;
 import print ;
@@ -43,6 +42,9 @@
 import sequence ;
 
 
+.debug-loading = [ MATCH ^(--debug-loading)$ : [ modules.peek : ARGV ] ] ;
+
+
 # Loads the Jamfile at the given location. After loading, project global file
 # and Jamfiles needed by the requested one will be loaded recursively. If the
 # Jamfile at that location is loaded already, does nothing. Returns the project
@@ -50,24 +52,24 @@
 #
 rule load ( jamfile-location )
 {
- if --debug-loading in [ modules.peek : ARGV ]
- {
- ECHO "Loading Jamfile at" '$(jamfile-location)' ;
- }
-
     local module-name = [ module-name $(jamfile-location) ] ;
- # If Jamfile is already loaded, don't try again.
+ # If Jamfile is already loaded, do not try again.
     if ! $(module-name) in $(.jamfile-modules)
     {
+ if $(.debug-loading)
+ {
+ ECHO Loading Jamfile at '$(jamfile-location)' ;
+ }
+
         load-jamfile $(jamfile-location) : $(module-name) ;
 
         # We want to make sure that child project are loaded only after parent
         # projects. In particular, because parent projects define attributes
- # which are inherited by children, and we don't want children to be
- # loaded before parent has defined everything.
+ # which are then inherited by children, and we do not want children to
+ # be loaded before parent has defined everything.
         #
         # While "build-project" and "use-project" can potentially refer to child
- # projects from parent projects, we don't immediately load child
+ # projects from parent projects, we do not immediately load child
         # projects when seeing those attributes. Instead, we record the minimal
         # information to be used only later.
         load-used-projects $(module-name) ;
@@ -80,13 +82,11 @@
 {
     local used = [ modules.peek $(module-name) : .used-projects ] ;
     local location = [ attribute $(module-name) location ] ;
- import project ;
     while $(used)
     {
         local id = $(used[1]) ;
- local where = $(used[2]) ;
-
- project.use $(id) : [ path.root [ path.make $(where) ] $(location) ] ;
+ local where = [ path.make $(used[2]) ] ;
+ register-id $(id) : [ load [ path.root $(where) $(location) ] ] ;
         used = $(used[3-]) ;
     }
 }
@@ -104,39 +104,16 @@
 rule load-parent ( location )
 {
     local found = [ path.glob-in-parents $(location) : $(JAMROOT) $(JAMFILE) ] ;
-
     if ! $(found)
     {
- ECHO error: Could not find parent for project at '$(location)' ;
- EXIT error: Did not find Jamfile.jam or Jamroot.jam in any parent
- directory. ;
+ import errors ;
+ errors.error Could not find parent "for" project at '$(location)' :
+ Did not find Jamfile.jam or Jamroot.jam "in" any parent directory. ;
     }
-
     return [ load $(found[1]:D) ] ;
 }
 
 
-# Makes the specified 'module' act as if it were a regularly loaded Jamfile at
-# 'location'. Reports an error if a Jamfile has already been loaded for that
-# location.
-#
-rule act-as-jamfile ( module : location )
-{
- if [ module-name $(location) ] in $(.jamfile-modules)
- {
- errors.error "Jamfile was already loaded for '$(location)'" ;
- }
- # Set up non-default mapping from location to module.
- .module.$(location) = $(module) ;
-
- # Add the location to the list of project locations so that we don't try to
- # reload the same Jamfile in the future.
- .jamfile-modules += [ module-name $(location) ] ;
-
- initialize $(module) : $(location) ;
-}
-
-
 # Returns the project module corresponding to the given project-id or plain
 # directory name. Returns nothing if such a project can not be found.
 #
@@ -158,7 +135,7 @@
         # If no project is registered for the given location, try to load it.
         # First see if we have a Jamfile. If not, then see if we might have a
         # project root willing to act as a Jamfile. In that case, project root
- # must be placed in the directory referred by id.
+ # must be placed in the directory referred to by id.
 
         project-module = [ module-name $(location) ] ;
         if ! $(project-module) in $(.jamfile-modules)
@@ -187,9 +164,25 @@
     if ! $(.module.$(jamfile-location))
     {
         # Root the path, so that locations are always unambiguous. Without this,
- # we can't decide if '../../exe/program1' and '.' are the same paths.
- jamfile-location = [ path.root $(jamfile-location) [ path.pwd ] ] ;
- .module.$(jamfile-location) = Jamfile<$(jamfile-location)> ;
+ # we can not decide if '../../exe/program1' and '.' are the same paths.
+ local normalized = [ path.root $(jamfile-location) [ path.pwd ] ] ;
+
+ # Quick & dirty fix to get the same module name when we supply two
+ # equivalent location paths, e.g. 'd:\Foo' & 'D:\fOo\bar\..' on Windows.
+ # Note that our current implementation will not work correctly if the
+ # given location references an empty folder, but in that case any later
+ # attempt to load a Jamfile from this location will fail anyway.
+ # FIXME: Implement this cleanly. Support for this type of path
+ # normalization already exists internally in Boost Jam and the current
+ # fix relies on the GLOB builtin rule using that support. Most likely we
+ # just need to add a new builtin rule to do this explicitly.
+ normalized = [ NORMALIZE_PATH $(normalized) ] ;
+ local glob-result = [ GLOB [ path.native $(normalized) ] : * ] ;
+ if $(glob-result)
+ {
+ normalized = $(glob-result[1]:D) ;
+ }
+ .module.$(jamfile-location) = Jamfile<$(normalized)> ;
     }
     return $(.module.$(jamfile-location)) ;
 }
@@ -204,11 +197,11 @@
 # Find the Jamfile at the given location. This returns the exact names of all
 # the Jamfiles in the given directory. The optional parent-root argument causes
 # this to search not the given directory but the ones above it up to the
-# directory given in it.
+# parent-root directory.
 #
 rule find-jamfile (
- dir # The directory(s) to look for a Jamfile.
- parent-root ? # Optional flag indicating to search for the parent Jamfile.
+ dir # The directory(s) to look for a Jamfile.
+ parent-root ? # Optional flag indicating to search for the parent Jamfile.
     : no-errors ?
     )
 {
@@ -241,7 +234,8 @@
     #
     if $(jamfile-to-load[2-])
     {
- local v2-jamfiles = [ MATCH (.*[Jj]amfile\\.v2)|(.*[Bb]uild\\.jam) : $(jamfile-to-load) ] ;
+ local v2-jamfiles = [ MATCH ^(.*[Jj]amfile\\.v2)|(.*[Bb]uild\\.jam)$ :
+ $(jamfile-to-load) ] ;
 
         if $(v2-jamfiles) && ! $(v2-jamfiles[2])
         {
@@ -261,9 +255,10 @@
     #
     if ! $(no-errors) && ! $(jamfile-to-load)
     {
+ import errors ;
         errors.error Unable to load Jamfile.
             : Could not find a Jamfile in directory '$(dir)'.
- : Attempted to find it with pattern '"$(JAMFILE:J= )"'.
+ : Attempted to find it with pattern '$(JAMFILE:J=" ")'.
             : Please consult the documentation at 'http://www.boost.org'. ;
     }
 
@@ -275,10 +270,7 @@
 # the file as indicated by the JAMFILE patterns. Effect of calling this rule
 # twice with the same 'dir' is undefined.
 #
-local rule load-jamfile (
- dir # The directory of the project Jamfile.
- : jamfile-module
- )
+local rule load-jamfile ( dir : jamfile-module )
 {
     # See if the Jamfile is where it should be.
     #
@@ -287,25 +279,26 @@
     {
         jamfile-to-load = [ find-jamfile $(dir) ] ;
     }
-
+
     if $(jamfile-to-load[2])
     {
- errors.error "Multiple Jamfiles found at '$(dir)'"
- : "Filenames are: " $(jamfile-to-load:D=) ;
+ import errors ;
+ errors.error "Multiple Jamfiles found at '$(dir)'" :
+ "Filenames are: " $(jamfile-to-load:D=) ;
     }
-
- # Now load the Jamfile in it's own context.
- # The call to 'initialize' may load parent Jamfile, which might have
- # 'use-project' statement that causes a second attempt to load the
- # same project we're loading now. Checking inside .jamfile-modules
- # prevents that second attempt from messing up.
+
+ # Now load the Jamfile in its own context.
+ # The call to 'initialize' may load the parent Jamfile, which might contain
+ # a 'use-project' or a 'project.load' call, causing a second attempt to load
+ # the same project we are loading now. Checking inside .jamfile-modules
+ # prevents that second attempt from messing things up.
     if ! $(jamfile-module) in $(.jamfile-modules)
     {
+ local previous-project = $(.current-project) ;
 
         # Initialize the Jamfile module before loading.
- #
- initialize $(jamfile-module) : [ path.parent $(jamfile-to-load) ]
- : $(jamfile-to-load:BS) ;
+ initialize $(jamfile-module) : [ path.parent $(jamfile-to-load) ] :
+ $(jamfile-to-load:BS) ;
 
         if ! $(jamfile-module) in $(.jamfile-modules)
         {
@@ -314,8 +307,9 @@
             local saved-project = $(.current-project) ;
 
             mark-as-user $(jamfile-module) ;
- modules.load $(jamfile-module) : [ path.native $(jamfile-to-load) ] : . ;
- if [ MATCH ($(JAMROOT)) : $(jamfile-to-load:BS) ]
+ modules.load $(jamfile-module) : [ path.native $(jamfile-to-load) ]
+ : . ;
+ if [ MATCH ^($(JAMROOT))$ : $(jamfile-to-load:BS) ]
             {
                 jamfile = [ find-jamfile $(dir) : no-errors ] ;
                 if $(jamfile)
@@ -327,24 +321,26 @@
             # Now do some checks.
             if $(.current-project) != $(saved-project)
             {
- errors.error "The value of the .current-project variable has magically"
- : "changed after loading a Jamfile. This means some of the targets"
- : "might be defined in the wrong project."
- : "after loading" $(jamfile-module)
- : "expected value" $(saved-project)
- : "actual value" $(.current-project) ;
+ import errors ;
+ errors.error
+ The value of the .current-project variable has magically
+ : changed after loading a Jamfile. This means some of the
+ : targets might be defined in the wrong project.
+ : after loading $(jamfile-module)
+ : expected value $(saved-project)
+ : actual value $(.current-project) ;
             }
 
+ end-load $(previous-project) ;
+
             if $(.global-build-dir)
             {
- local id = [ attribute $(jamfile-module) id ] ;
- local project-root = [ attribute $(jamfile-module) project-root ] ;
- local location = [ attribute $(jamfile-module) location ] ;
-
- if $(location) && $(project-root) = $(dir)
+ if [ attribute $(jamfile-module) location ] && ! [ attribute
+ $(jamfile-module) id ]
                 {
- # This is Jamroot.
- if ! $(id)
+ local project-root = [ attribute $(jamfile-module)
+ project-root ] ;
+ if $(project-root) = $(dir)
                     {
                         ECHO "warning: the --build-dir option was specified" ;
                         ECHO "warning: but Jamroot at '$(dir)'" ;
@@ -358,6 +354,31 @@
 }
 
 
+# Called when done loading a project module. Restores the current project to its
+# previous value and does some additional checking to make sure our 'currently
+# loaded project' identifier does not get left with an invalid value.
+#
+rule end-load ( previous-project ? )
+{
+ if ! $(.current-project)
+ {
+ import errors ;
+ errors.error Ending project loading requested when there was no project
+ currently being loaded. ;
+ }
+
+ if ! $(previous-project) && $(.saved-current-project)
+ {
+ import errors ;
+ errors.error Ending project loading requested with no 'previous project'
+ when there were other projects still marked as being loaded
+ recursively. ;
+ }
+
+ .current-project = $(previous-project) ;
+}
+
+
 rule mark-as-user ( module-name )
 {
     if USER_MODULE in [ RULENAMES ]
@@ -380,7 +401,7 @@
 }
 
 
-.global-build-dir = [ MATCH --build-dir=(.*) : [ modules.peek : ARGV ] ] ;
+.global-build-dir = [ MATCH ^--build-dir=(.*)$ : [ modules.peek : ARGV ] ] ;
 if $(.global-build-dir)
 {
     # If the option is specified several times, take the last value.
@@ -397,7 +418,7 @@
     : basename ?
     )
 {
- if --debug-loading in [ modules.peek : ARGV ]
+ if $(.debug-loading)
     {
         ECHO "Initializing project '$(module-name)'" ;
     }
@@ -420,68 +441,69 @@
     else if $(module-name) = project-config
     {
         parent-module = user-config ;
- }
- else
+ }
+ else if $(location) && ! [ MATCH ^($(JAMROOT))$ : $(basename) ]
+ {
+ # We search for parent/jamroot only if this is a jamfile project, i.e.
+ # if is not a standalone or a jamroot project.
+ parent-module = [ load-parent $(location) ] ;
+ }
+ else if $(location)
     {
- # We search for parent/project-root only if Jamfile was specified, i.e.
- # if the project is not standalone.
- if $(location) && ! [ MATCH ($(JAMROOT)) : $(basename) ]
+ # We have a jamroot project. Inherit from user-config (or project-config
+ # if it exists).
+ if $(project-config.attributes)
         {
- parent-module = [ load-parent $(location) ] ;
+ parent-module = project-config ;
         }
         else
         {
- # It's either jamroot or standalone project. If it's jamroot,
- # inherit from user-config.
- if $(location)
- {
- # If project-config module exist, inherit from it.
- if $(project-config.attributes)
- {
- parent-module = project-config ;
- }
- else
- {
- parent-module = user-config ;
- }
- jamroot = true ;
- }
+ parent-module = user-config ;
         }
+ jamroot = true ;
     }
 
     # TODO: need to consider if standalone projects can do anything but define
- # prebuilt targets. If so, we need to give it a more sensible "location", so
- # that source paths are correct.
+ # prebuilt targets. If so, we need to give them a more sensible "location",
+ # so that source paths are correct.
     location ?= "" ;
     # Create the module for the Jamfile first.
     module $(module-name)
     {
     }
 
- # load-parent can end up loading this module again.
- # Make sure this isn't duplicated.
- if ! $($(module-name).attributes) {
-
+ # load-parent can end up loading this module again. Make sure this is not
+ # duplicated.
+ if ! $($(module-name).attributes)
+ {
         $(module-name).attributes = [ new project-attributes $(location)
             $(module-name) ] ;
         local attributes = $($(module-name).attributes) ;
 
         if $(location)
         {
- $(attributes).set source-location : [ path.make $(location) ] : exact ;
+ $(attributes).set source-location : [ path.make $(location) ] :
+ exact ;
         }
- else if ! $(module-name) in test-config site-config user-config project-config
+ else
         {
- # This is a standalone project with known location. Set source location
- # so that it can declare targets. This is intended so that you can put
- # a .jam file in your sources and use it via 'using'. Standard modules
- # (in 'tools' subdir) may not assume source dir is set.
- local s = [ modules.binding $(module-name) ] ;
- if ! $(s)
+ local cfgs = project site test user ;
+ if ! $(module-name) in $(cfgs)-config
             {
- errors.error "Could not determine project location $(module-name)" ;
- }
- $(attributes).set source-location : $(s:D) : exact ;
+ # This is a standalone project with known location. Set its
+ # source location so it can declare targets. This is needed so
+ # you can put a .jam file with your sources and use it via
+ # 'using'. Standard modules (in the 'tools' subdir) may not
+ # assume source dir is set.
+ local s = [ modules.binding $(module-name) ] ;
+ if ! $(s)
+ {
+ import errors ;
+ errors.error Could not determine project location
+ $(module-name) ;
+ }
+ $(attributes).set source-location : $(s:D) : exact ;
+ }
         }
 
         $(attributes).set requirements : [ property-set.empty ] : exact ;
@@ -501,6 +523,10 @@
         if $(jamroot)
         {
             $(attributes).set project-root : $(location) : exact ;
+ if ! $(.first-project-root)
+ {
+ .first-project-root = $(module-name) ;
+ }
         }
 
         local parent ;
@@ -511,14 +537,14 @@
 
         if ! $(.target.$(module-name))
         {
- .target.$(module-name) = [ new project-target $(module-name)
- : $(module-name) $(parent)
- : [ attribute $(module-name) requirements ] ] ;
+ local requirements = [ attribute $(module-name) requirements ] ;
+ .target.$(module-name) = [ new project-target $(module-name) :
+ $(module-name) $(parent) : $(requirements) ] ;
 
- if --debug-loading in [ modules.peek : ARGV ]
+ if $(.debug-loading)
             {
- ECHO "Assigned project target" $(.target.$(module-name))
- "to '$(module-name)'" ;
+ ECHO Assigned project target $(.target.$(module-name)) to
+ '$(module-name)' ;
             }
         }
     }
@@ -536,17 +562,17 @@
     # Parent module might be locationless configuration module.
     if [ modules.binding $(parent-module) ]
     {
- $(attributes).set parent : [ path.parent
- [ path.make [ modules.binding $(parent-module) ] ] ] ;
+ $(attributes).set parent :
+ [ path.parent [ path.make [ modules.binding $(parent-module) ] ] ] ;
     }
- local v = [ $(pattributes).get project-root ] ;
- $(attributes).set project-root : $(v) : exact ;
- $(attributes).set default-build
- : [ $(pattributes).get default-build ] ;
- $(attributes).set requirements
- : [ $(pattributes).get requirements ] : exact ;
- $(attributes).set usage-requirements
- : [ $(pattributes).get usage-requirements ] : exact ;
+ $(attributes).set project-root :
+ [ $(pattributes).get project-root ] : exact ;
+ $(attributes).set default-build :
+ [ $(pattributes).get default-build ] ;
+ $(attributes).set requirements :
+ [ $(pattributes).get requirements ] : exact ;
+ $(attributes).set usage-requirements :
+ [ $(pattributes).get usage-requirements ] : exact ;
 
     local parent-build-dir = [ $(pattributes).get build-dir ] ;
     if $(parent-build-dir)
@@ -567,11 +593,57 @@
 }
 
 
-# Associate the given id with the given project module.
+# Returns whether the given string is a valid registered project id.
+#
+rule is-registered-id ( id )
+{
+ return $($(id).jamfile-module) ;
+}
+
+
+# Associate the given id with the given project module. Returns the possibly
+# corrected project id.
 #
 rule register-id ( id : module )
 {
+ id = [ path.root $(id) / ] ;
+
+ if [ MATCH (//) : $(id) ]
+ {
+ import errors ;
+ errors.user-error Project id may not contain two consecutive slash
+ characters (project id: '$(id)'). ;
+ }
+
+ local orig-module = $($(id).jamfile-module) ;
+ if $(orig-module) && $(orig-module) != $(module)
+ {
+ local new-file = [ modules.peek $(module) : __file__ ] ;
+ local new-location = [ project.attribute $(module) location ] ;
+
+ local orig-file = [ modules.peek $(orig-module) : __file__ ] ;
+ local orig-main-id = [ project.attribute $(orig-module) id ] ;
+ local orig-location = [ project.attribute $(orig-module) location ] ;
+ local orig-project = [ target $(orig-module) ] ;
+ local orig-name = [ $(orig-project).name ] ;
+
+ import errors ;
+ errors.user-error Attempt to redeclare already registered project id
+ '$(id)'.
+ : Original project:
+ : " " Name: $(orig-name:E=---)
+ : " " Module: $(orig-module)
+ : " " Main id: $(orig-main-id:E=---)
+ : " " File: $(orig-file:E=---)
+ : " " Location: $(orig-location:E=---)
+ : New project:
+ : " " Module: $(module)
+ : " " File: $(new-file:E=---)
+ : " " Location: $(new-location:E=---) ;
+ }
+
     $(id).jamfile-module = $(module) ;
+ return $(id) ;
 }
 
 
@@ -582,13 +654,12 @@
 #
 class project-attributes
 {
- import property ;
- import property-set ;
- import errors ;
     import path ;
     import print ;
- import sequence ;
     import project ;
+ import property ;
+ import property-set ;
+ import sequence ;
 
     rule __init__ ( location project-module )
     {
@@ -615,13 +686,12 @@
 
             if $(result[1]) = "@error"
             {
+ import errors : error : errors.error ;
                 errors.error Requirements for project at '$(self.location)'
                     conflict with parent's. : Explanation: $(result[2-]) ;
             }
- else
- {
- self.requirements = $(result) ;
- }
+
+ self.requirements = $(result) ;
         }
         else if $(attribute) = "usage-requirements"
         {
@@ -636,11 +706,12 @@
             local non-free = [ property.remove free : $(unconditional) ] ;
             if $(non-free)
             {
+ import errors : error : errors.error ;
                 errors.error usage-requirements $(specification) have non-free
                     properties $(non-free) ;
             }
- local t = [ property.translate-paths $(specification)
- : $(self.location) ] ;
+ local t = [ property.translate-paths $(specification) :
+ $(self.location) ] ;
             if $(self.usage-requirements)
             {
                 self.usage-requirements = [ property-set.create
@@ -666,18 +737,18 @@
         }
         else if $(attribute) = "build-dir"
         {
- self.build-dir = [ path.root
- [ path.make $(specification) ] $(self.location) ] ;
+ self.build-dir = [ path.root [ path.make $(specification) ]
+ $(self.location) ] ;
         }
         else if $(attribute) = "id"
         {
- id = [ path.root $(specification) / ] ;
- project.register-id $(id) : $(self.project-module) ;
- self.id = $(id) ;
+ self.id = [ project.register-id $(specification) :
+ $(self.project-module) ] ;
         }
         else if ! $(attribute) in "default-build" "location" "parent"
             "projects-to-build" "project-root" "source-location"
         {
+ import errors : error : errors.error ;
             errors.error Invalid project attribute '$(attribute)' specified for
                 project at '$(self.location)' ;
         }
@@ -694,29 +765,52 @@
         return $(self.$(attribute)) ;
     }
 
+ # Returns whether these attributes belong to a Jamroot project module.
+ #
+ rule is-jamroot ( )
+ {
+ if $(self.location) && $(self.project-root) = $(self.location)
+ {
+ return true ;
+ }
+ }
+
     # Prints the project attributes.
     #
     rule print ( )
     {
- local id = $(self.id) ; id ?= (none) ;
- local parent = $(self.parent) ; parent ?= (none) ;
- print.section "'"$(id)"'" ;
+ local id = '$(self.id)' ;
+ print.section $(id:E=(none)) ;
         print.list-start ;
- print.list-item "Parent project:" $(parent) ;
+ print.list-item "Parent project:" $(self.parent:E=(none)) ;
         print.list-item "Requirements:" [ $(self.requirements).raw ] ;
         print.list-item "Default build:" $(self.default-build) ;
         print.list-item "Source location:" $(self.source-location) ;
- print.list-item "Projects to build:"
- [ sequence.insertion-sort $(self.projects-to-build) ] ;
+ print.list-item "Projects to build:" [ sequence.insertion-sort
+ $(self.projects-to-build) ] ;
         print.list-end ;
     }
 }
 
 
+# Returns the build directory for standalone projects
+#
+rule standalone-build-dir ( )
+{
+ project = [ target $(.first-project-root) ] ;
+ return [ path.join [ $(project).build-dir ] standalone ] ;
+}
+
 # Returns the project which is currently being loaded.
 #
 rule current ( )
 {
+ if ! $(.current-project)
+ {
+ import errors ;
+ errors.error Reference to the project currently being loaded requested
+ when there was no project module being loaded. ;
+ }
     return $(.current-project) ;
 }
 
@@ -754,42 +848,52 @@
 }
 
 
-# Returns the project target corresponding to the 'project-module'.
+# Returns whether a project module is one of Boost Build's configuration
+# modules.
 #
-rule target ( project-module )
+rule is-config-module ( project )
 {
- if ! $(.target.$(project-module))
+ local cfgs = project site test user ;
+ if $(project) in $(cfgs)-config
     {
- .target.$(project-module) = [ new project-target $(project-module)
- : $(project-module)
- : [ attribute $(project-module) requirements ] ] ;
+ return true ;
     }
- return $(.target.$(project-module)) ;
 }
 
 
-# Use/load a project.
+# Returns whether a project module is a Jamroot project module.
 #
-rule use ( id : location )
+rule is-jamroot-module ( project )
 {
- local saved-project = $(.current-project) ;
- local project-module = [ project.load $(location) ] ;
- local declared-id = [ project.attribute $(project-module) id ] ;
+ return [ $($(project).attributes).is-jamroot ] ;
+}
+
 
- if ! $(declared-id) || $(declared-id) != $(id)
+# Returns a project's parent jamroot module. Returns nothing if there is no such
+# module, i.e. if this is a standalone project or one of the internal Boost
+# Build configuration projects.
+#
+rule get-jamroot-module ( project )
+{
+ local jamroot-location = [ attribute $(project) project-root ] ;
+ if $(jamroot-location)
     {
- # The project at 'location' either has no id or that id is not equal to
- # the 'id' parameter.
- if $($(id).jamfile-module) && ( $($(id).jamfile-module) !=
- $(project-module) )
- {
- errors.user-error Attempt to redeclare already existing project id
- '$(id)'
- location '$(location)' ;
- }
- $(id).jamfile-module = $(project-module) ;
+ return [ module-name $(jamroot-location) ] ;
+ }
+}
+
+
+# Returns the project target corresponding to the 'project-module'.
+#
+rule target ( project-module )
+{
+ if ! $(.target.$(project-module))
+ {
+ import errors ;
+ errors.user-error Project target requested but not yet assigned for
+ module '$(project-module)'. ;
     }
- .current-project = $(saved-project) ;
+ return $(.target.$(project-module)) ;
 }
 
 
@@ -826,7 +930,8 @@
         # Create the project itself, i.e. the attributes. All extensions are
         # created in the "/ext" project space.
         project /ext/$(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
- $(9) ;
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17)
+ : $(18) : $(19) ;
         local attributes = [ project.attributes $(__name__) ] ;
 
         # Inherit from the root project of whomever is defining us.
@@ -856,13 +961,13 @@
             # Otherwise, use full path just to avoid any ambiguities.
             local rel = [ path.relative $(p) $(location) : no-error ] ;
             if $(rel) = not-a-child
- {
+ {
                 result += [ path.root $(p) [ path.pwd ] ] ;
             }
             else
             {
                 result += $(rel) ;
- }
+ }
         }
     }
     else
@@ -881,11 +986,13 @@
 #
 module project-rules
 {
+ import modules ;
+
     rule using ( toolset-module : * )
     {
         import toolset ;
- import modules ;
- import project ;
+
+ local saved-project = [ modules.peek project : .current-project ] ;
 
         # Temporarily change the search path so the module referred to by
         # 'using' can be placed in the same directory as Jamfile. User will
@@ -895,33 +1002,38 @@
         local caller = [ CALLER_MODULE ] ;
         local caller-location = [ modules.binding $(caller) ] ;
         modules.poke : BOOST_BUILD_PATH : $(caller-location:D) $(x) ;
- toolset.using $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ toolset.using $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17)
+ : $(18) : $(19) ;
         modules.poke : BOOST_BUILD_PATH : $(x) ;
 
- # The above might have clobbered .current-project. Restore the correct
- # value.
- modules.poke project : .current-project
- : [ project.target $(caller) ] ;
+ # The above might have clobbered .current-project in case it caused a
+ # new project instance to be created (which would then automatically
+ # get set as the 'current' project). Restore the correct value so any
+ # main targets declared after this do not get mapped to the loaded
+ # module's project.
+ modules.poke project : .current-project : $(saved-project) ;
     }
 
- import modules ;
-
     rule import ( * : * : * )
     {
- modules.import project ;
-
         local caller = [ CALLER_MODULE ] ;
- local saved = [ modules.peek project : .current-project ] ;
+ local saved-project = [ modules.peek project : .current-project ] ;
         module $(caller)
         {
             modules.import $(1) : $(2) : $(3) ;
         }
- modules.poke project : .current-project : $(saved) ;
+
+ # The above might have clobbered .current-project in case it caused a
+ # new project instance to be created (which would then automatically
+ # get set as the 'current' project). Restore the correct value so any
+ # main targets declared after this do not get mapped to the loaded
+ # module's project.
+ modules.poke project : .current-project : $(saved-project) ;
     }
 
     rule project ( id ? : options * : * )
     {
- import errors ;
         import path ;
         import project ;
 
@@ -929,12 +1041,12 @@
         local attributes = [ project.attributes $(caller) ] ;
         if $(id)
         {
- $(attributes).set id : $(id) ;
+ $(attributes).set id : $(id) ;
         }
 
         local explicit-build-dir ;
 
- for n in 2 3 4 5 6 7 8 9
+ for n in 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
         {
             local option = $($(n)) ;
             if $(option)
@@ -948,8 +1060,7 @@
         }
 
         # If '--build-dir' is specified, change the build dir for the project.
- local global-build-dir =
- [ modules.peek project : .global-build-dir ] ;
+ local global-build-dir = [ modules.peek project : .global-build-dir ] ;
 
         if $(global-build-dir)
         {
@@ -960,8 +1071,9 @@
             # weird or wrong consequences.
             if $(location) && $(location) = [ $(attributes).get project-root ]
             {
- # Re-read the project id, since it might have been changed in
- # the project's attributes.
+ # Re-read the project id, since it might have been modified a
+ # bit when setting the project's id attribute, e.g. might have
+ # been prefixed by a slash if it was not already.
                 id = [ $(attributes).get id ] ;
                 # This is Jamroot.
                 if $(id)
@@ -969,14 +1081,15 @@
                     if $(explicit-build-dir) &&
                         [ path.is-rooted $(explicit-build-dir) ]
                     {
+ import errors ;
                         errors.user-error Absolute directory specified via
                             'build-dir' project attribute : Do not know how to
                             combine that with the --build-dir option. ;
                     }
                     # Strip the leading slash from id.
- local rid = [ MATCH /(.*) : $(id) ] ;
- local p = [ path.join
- $(global-build-dir) $(rid) $(explicit-build-dir) ] ;
+ local rid = [ MATCH ^/(.*) : $(id) ] ;
+ local p = [ path.join $(global-build-dir) $(rid)
+ $(explicit-build-dir) ] ;
 
                     $(attributes).set build-dir : $(p) : exact ;
                 }
@@ -986,6 +1099,7 @@
                 # Not Jamroot.
                 if $(explicit-build-dir)
                 {
+ import errors ;
                     errors.user-error When --build-dir is specified, the
                         'build-dir' project : attribute is allowed only for
                         top-level 'project' invocations ;
@@ -998,10 +1112,7 @@
     # normal variables but should not be changed. They are applied to every
     # child Jamfile.
     #
- rule constant (
- name # Variable name of the constant.
- : value + # Value of the constant.
- )
+ rule constant ( name : value + )
     {
         import project ;
         local caller = [ CALLER_MODULE ] ;
@@ -1013,10 +1124,7 @@
     # is adjusted to be relative to the invocation directory. The given value
     # path is taken to be either absolute, or relative to this project root.
     #
- rule path-constant (
- name # Variable name of the constant.
- : value + # Value of the constant.
- )
+ rule path-constant ( name : value + )
     {
         import project ;
         local caller = [ CALLER_MODULE ] ;
@@ -1026,12 +1134,10 @@
 
     rule use-project ( id : where )
     {
- import modules ;
         # See comment in 'load' for explanation.
         local caller = [ CALLER_MODULE ] ;
- modules.poke $(caller) : .used-projects :
- [ modules.peek $(caller) : .used-projects ]
- $(id) $(where) ;
+ modules.poke $(caller) : .used-projects : [ modules.peek $(caller) :
+ .used-projects ] $(id) $(where) ;
     }
 
     rule build-project ( dir )
@@ -1039,7 +1145,6 @@
         import project ;
         local caller = [ CALLER_MODULE ] ;
         local attributes = [ project.attributes $(caller) ] ;
-
         local now = [ $(attributes).get projects-to-build ] ;
         $(attributes).set projects-to-build : $(now) $(dir) ;
     }
@@ -1064,9 +1169,9 @@
         for local n in $(target-names)
         {
             $(t).mark-target-as-always $(n) ;
- }
+ }
     }
-
+
     rule glob ( wildcards + : excludes * )
     {
         import project ;
@@ -1077,9 +1182,9 @@
     rule glob-tree ( wildcards + : excludes * )
     {
         import project ;
-
         if $(wildcards:D) || $(excludes:D)
         {
+ import errors ;
             errors.user-error The patterns to 'glob-tree' may not include
                 directory ;
         }
@@ -1106,16 +1211,18 @@
             return $(condition):$(requirements) ;
         }
     }
-
+
     rule option ( name : value )
     {
         local m = [ CALLER_MODULE ] ;
- if $(m) != site-config && $(m) != user-config && $(m) != project-config
+ local cfgs = project site test user ;
+ if ! $(m) in $(cfgs)-config
         {
             import errors ;
- errors.error "The 'option' rule may be used only in site-config or user-config" ;
- }
+ errors.error The 'option' rule may only be used "in" Boost Build
+ configuration files. ;
+ }
         import option ;
         option.set $(name) : $(value) ;
- }
+ }
 }

Modified: branches/release/tools/build/v2/build/project.py
==============================================================================
--- branches/release/tools/build/v2/build/project.py (original)
+++ branches/release/tools/build/v2/build/project.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,42 +1,43 @@
 # Status: ported.
 # Base revision: 64488
 
-# Copyright 2002, 2003 Dave Abrahams
-# Copyright 2002, 2005, 2006 Rene Rivera
-# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
-# 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)
-
-# Implements project representation and loading.
-# Each project is represented by
-# - a module where all the Jamfile content live.
-# - an instance of 'project-attributes' class.
-# (given module name, can be obtained by 'attributes' rule)
-# - an instance of 'project-target' class (from targets.jam)
-# (given a module name, can be obtained by 'target' rule)
+# Copyright 2002, 2003 Dave Abrahams
+# Copyright 2002, 2005, 2006 Rene Rivera
+# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
+# 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)
+
+# Implements project representation and loading. Each project is represented
+# by:
+# - a module where all the Jamfile content live.
+# - an instance of 'project-attributes' class.
+# (given a module name, can be obtained using the 'attributes' rule)
+# - an instance of 'project-target' class (from targets.jam)
+# (given a module name, can be obtained using the 'target' rule)
 #
-# Typically, projects are created as result of loading Jamfile, which is
-# do by rules 'load' and 'initialize', below. First, module for Jamfile
-# is loaded and new project-attributes instance is created. Some rules
-# necessary for project are added to the module (see 'project-rules' module)
-# at the bottom of this file.
-# Default project attributes are set (inheriting attributes of parent project, if
-# it exists). After that, Jamfile is read. It can declare its own attributes,
-# via 'project' rule, which will be combined with already set attributes.
+# Typically, projects are created as result of loading a Jamfile, which is done
+# by rules 'load' and 'initialize', below. First, module for Jamfile is loaded
+# and new project-attributes instance is created. Some rules necessary for
+# project are added to the module (see 'project-rules' module) at the bottom of
+# this file. Default project attributes are set (inheriting attributes of
+# parent project, if it exists). After that the Jamfile is read. It can declare
+# its own attributes using the 'project' rule which will be combined with any
+# already set attributes.
 #
+# The 'project' rule can also declare a project id which will be associated
+# with the project module.
 #
-# The 'project' rule can also declare project id, which will be associated with
-# the project module.
+# There can also be 'standalone' projects. They are created by calling
+# 'initialize' on an arbitrary module and not specifying their location. After
+# the call, the module can call the 'project' rule, declare main targets and
+# behave as a regular project except that, since it is not associated with any
+# location, it should only declare prebuilt targets.
 #
-# There can also be 'standalone' projects. They are created by calling 'initialize'
-# on arbitrary module, and not specifying location. After the call, the module can
-# call 'project' rule, declare main target and behave as regular projects. However,
-# since it's not associated with any location, it's better declare only prebuilt
-# targets.
-#
-# The list of all loaded Jamfile is stored in variable .project-locations. It's possible
-# to obtain module name for a location using 'module-name' rule. The standalone projects
-# are not recorded, the only way to use them is by project id.
+# The list of all loaded Jamfiles is stored in the .project-locations variable.
+# It is possible to obtain a module name for a location using the 'module-name'
+# rule. Standalone projects are not recorded and can only be references using
+# their project id.
 
 import b2.util.path
 from b2.build import property_set, property
@@ -64,7 +65,7 @@
 
         # The target corresponding to the project being loaded now
         self.current_project = None
-
+
         # The set of names of loaded project modules
         self.jamfile_modules = {}
 
@@ -130,34 +131,33 @@
         absolute = os.path.normpath(absolute)
         jamfile_location = b2.util.path.relpath(os.getcwd(), absolute)
 
- if "--debug-loading" in self.manager.argv():
- print "Loading Jamfile at '%s'" % jamfile_location
-
-
         mname = self.module_name(jamfile_location)
- # If Jamfile is already loaded, don't try again.
+ # If Jamfile is already loaded, do not try again.
         if not mname in self.jamfile_modules:
-
+
+ if "--debug-loading" in self.manager.argv():
+ print "Loading Jamfile at '%s'" % jamfile_location
+
             self.load_jamfile(jamfile_location, mname)
-
+
             # We want to make sure that child project are loaded only
             # after parent projects. In particular, because parent projects
- # define attributes whch are inherited by children, and we don't
+ # define attributes which are inherited by children, and we do not
             # want children to be loaded before parents has defined everything.
             #
             # While "build-project" and "use-project" can potentially refer
- # to child projects from parent projects, we don't immediately
+ # to child projects from parent projects, we do not immediately
             # load child projects when seing those attributes. Instead,
             # we record the minimal information that will be used only later.
-
+
             self.load_used_projects(mname)
-
+
         return mname
 
     def load_used_projects(self, module_name):
         # local used = [ modules.peek $(module-name) : .used-projects ] ;
         used = self.used_projects[module_name]
-
+
         location = self.attribute(module_name, "location")
         for u in used:
             id = u[0]
@@ -170,32 +170,14 @@
         Issues an error if nothing is found."""
 
         found = b2.util.path.glob_in_parents(
- location, self.JAMROOT + self.JAMFILE)
+ location, self.JAMROOT + self.JAMFILE)
 
         if not found:
             print "error: Could not find parent for project at '%s'" % location
             print "error: Did not find Jamfile or project-root.jam in any parent directory."
             sys.exit(1)
-
- return self.load(os.path.dirname(found[0]))
 
- def act_as_jamfile(self, module, location):
- """Makes the specified 'module' act as if it were a regularly loaded Jamfile
- at 'location'. If Jamfile is already located for that location, it's an
- error."""
-
- if self.module_name(location) in self.jamfile_modules:
- self.manager.errors()(
- "Jamfile was already loaded for '%s'" % location)
-
- # Set up non-default mapping from location to module.
- self.location2module[location] = module
-
- # Add the location to the list of project locations
- # so that we don't try to load Jamfile in future
- self.jamfile_modules.append(location)
-
- self.initialize(module, location)
+ return self.load(os.path.dirname(found[0]))
 
     def find(self, name, current_location):
         """Given 'name' which can be project-id or plain directory name,
@@ -214,7 +196,7 @@
             # load it. First see if we have Jamfile. If not we might have project
             # root, willing to act as Jamfile. In that case, project-root
             # must be placed in the directory referred by id.
-
+
             project_module = self.module_name(location)
             if not project_module in self.jamfile_modules:
                 if b2.util.path.glob([location], self.JAMROOT + self.JAMFILE):
@@ -244,7 +226,7 @@
         exact names of all the Jamfiles in the given directory. The optional
         parent-root argument causes this to search not the given directory
         but the ones above it up to the directory given in it."""
-
+
         # Glob for all the possible Jamfiles according to the match pattern.
         #
         jamfile_glob = None
@@ -277,7 +259,7 @@
                 for j in jamfile_glob:
                     print " -", j
                 print "Loading the first one"
-
+
         # Could not find it, error.
         if not no_errors and not jamfile_glob:
             self.manager.errors()(
@@ -289,12 +271,12 @@
 
         if jamfile_glob:
             return jamfile_glob[0]
-
+
     def load_jamfile(self, dir, jamfile_module):
         """Load a Jamfile at the given directory. Returns nothing.
         Will attempt to load the file as indicated by the JAMFILE patterns.
         Effect of calling this rule twice with the same 'dir' is underfined."""
-
+
         # See if the Jamfile is where it should be.
         is_jamroot = False
         jamfile_to_load = b2.util.path.glob([dir], self.JAMROOT)
@@ -314,8 +296,8 @@
             dir = "."
 
         self.used_projects[jamfile_module] = []
-
- # Now load the Jamfile in it's own context.
+
+ # Now load the Jamfile in it's own context.
         # The call to 'initialize' may load parent Jamfile, which might have
         # 'use-project' statement that causes a second attempt to load the
         # same project we're loading now. Checking inside .jamfile-modules
@@ -324,7 +306,7 @@
             self.jamfile_modules[jamfile_module] = True
 
             # Initialize the jamfile module before loading.
- #
+ #
             self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load))
 
             saved_project = self.current_project
@@ -336,7 +318,7 @@
                 jamfile = self.find_jamfile(dir, no_errors=True)
                 if jamfile:
                     bjam.call("load", jamfile_module, jamfile)
-
+
         # Now do some checks
         if self.current_project != saved_project:
             self.manager.errors()(
@@ -346,7 +328,7 @@
 after loading %s
 expected value %s
 actual value %s""" % (jamfile_module, saved_project, self.current_project))
-
+
         if self.global_build_dir:
             id = self.attributeDefault(jamfile_module, "id", None)
             project_root = self.attribute(jamfile_module, "project-root")
@@ -367,7 +349,7 @@
         """Loads 'file' as standalone project that has no location
         associated with it. This is mostly useful for user-config.jam,
         which should be able to define targets, but although it has
- some location in filesystem, we don't want any build to
+ some location in filesystem, we do not want any build to
         happen in user's HOME, for example.
 
         The caller is required to never call this method twice on
@@ -377,7 +359,7 @@
         self.used_projects[jamfile_module] = []
         bjam.call("load", jamfile_module, file)
         self.load_used_projects(jamfile_module)
-
+
     def is_jamroot(self, basename):
         match = [ pat for pat in self.JAMROOT if re.match(pat, basename)]
         if match:
@@ -387,7 +369,7 @@
 
     def initialize(self, module_name, location=None, basename=None):
         """Initialize the module for a project.
-
+
         module-name is the name of the project module.
         location is the location (directory) of the project to initialize.
                  If not specified, stanalone project will be initialized
@@ -413,7 +395,7 @@
             # so that it can declare targets. This is intended so that you can put
             # a .jam file in your sources and use it via 'using'. Standard modules
             # (in 'tools' subdir) may not assume source dir is set.
- module = sys.modules[module_name]
+ module = sys.modules[module_name]
             attributes.set("source-location", self.loaded_tool_module_path_[module_name], exact=1)
             python_standalone = True
 
@@ -423,7 +405,7 @@
         attributes.set("projects-to-build", [], exact=True)
         attributes.set("project-root", None, exact=True)
         attributes.set("build-dir", None, exact=True)
-
+
         self.project_rules_.init_project(module_name, python_standalone)
 
         jamroot = False
@@ -439,7 +421,7 @@
         elif module_name == "project-config":
             parent_module = "user-config"
         elif location and not self.is_jamroot(basename):
- # We search for parent/project-root only if jamfile was specified
+ # We search for parent/project-root only if jamfile was specified
             # --- i.e
             # if the project is not standalone.
             parent_module = self.load_parent(location)
@@ -452,16 +434,16 @@
                     parent_module = "project-config"
                 else:
                     parent_module = "user-config" ;
-
+
                 jamroot = True ;
-
+
         if parent_module:
             self.inherit_attributes(module_name, parent_module)
             attributes.set("parent-module", parent_module, exact=1)
 
         if jamroot:
             attributes.set("project-root", location, exact=1)
-
+
         parent = None
         if parent_module:
             parent = self.target(parent_module)
@@ -469,7 +451,7 @@
         if not self.module2target.has_key(module_name):
             target = b2.build.targets.ProjectTarget(self.manager,
                 module_name, module_name, parent,
- self.attribute(module_name,"requirements"),
+ self.attribute(module_name, "requirements"),
                 # FIXME: why we need to pass this? It's not
                 # passed in jam code.
                 self.attribute(module_name, "default-build"))
@@ -483,15 +465,15 @@
 
         attributes = self.module2attributes[project_module]
         pattributes = self.module2attributes[parent_module]
-
+
         # Parent module might be locationless user-config.
         # FIXME:
         #if [ modules.binding $(parent-module) ]
- #{
- # $(attributes).set parent : [ path.parent
+ #{
+ # $(attributes).set parent : [ path.parent
         # [ path.make [ modules.binding $(parent-module) ] ] ] ;
         # }
-
+
         attributes.set("project-root", pattributes.get("project-root"), exact=True)
         attributes.set("default-build", pattributes.get("default-build"), exact=True)
         attributes.set("requirements", pattributes.get("requirements"), exact=True)
@@ -499,7 +481,7 @@
                        pattributes.get("usage-requirements"), exact=1)
 
         parent_build_dir = pattributes.get("build-dir")
-
+
         if parent_build_dir:
         # Have to compute relative path from parent dir to our dir
         # Convert both paths to absolute, since we cannot
@@ -545,7 +527,7 @@
         """Returns the value of the specified attribute in the
         specified jamfile module."""
         return self.module2attributes[project].get(attribute)
- try:
+ try:
             return self.module2attributes[project].get(attribute)
         except:
             raise BaseException("No attribute '%s' for project" % (attribute, project))
@@ -561,7 +543,7 @@
             self.module2target[project_module] = \
                 b2.build.targets.ProjectTarget(project_module, project_module,
                               self.attribute(project_module, "requirements"))
-
+
         return self.module2target[project_module]
 
     def use(self, id, location):
@@ -594,7 +576,7 @@
 
         result = []
         callable = b2.util.path.__dict__[rule_name]
-
+
         paths = callable([location], wildcards, excludes)
         has_dir = 0
         for w in wildcards:
@@ -617,13 +599,13 @@
                 else:
                     # Otherwise, use full path just to avoid any ambiguities.
                     result.append(os.path.abspath(p))
-
+
         else:
             # There were not directory in wildcard, so the files are all
             # in the source directory of the project. Just drop the
             # directory, instead of making paths absolute.
             result = [os.path.basename(p) for p in paths]
-
+
         return result
 
     def load_module(self, name, extra_path=None):
@@ -673,7 +655,7 @@
 
         mname = name + "__for_jamfile"
         file = open(location)
- try:
+ try:
             # TODO: this means we'll never make use of .pyc module,
             # which might be a problem, or not.
             self.loaded_tool_module_path_[mname] = location
@@ -683,7 +665,7 @@
             return module
         finally:
             file.close()
-
+
 
 
 # FIXME:
@@ -696,12 +678,12 @@
 #{
 # # The caller is a standalone module for the extension.
 # local mod = [ CALLER_MODULE ] ;
-#
+#
 # # We need to do the rest within the extension module.
 # module $(mod)
 # {
 # import path ;
-#
+#
 # # Find the root project.
 # local root-project = [ project.current ] ;
 # root-project = [ $(root-project).project-module ] ;
@@ -711,23 +693,23 @@
 # {
 # root-project = [ project.attribute $(root-project) parent-module ] ;
 # }
-#
+#
 # # Create the project data, and bring in the project rules
 # # into the module.
 # project.initialize $(__name__) :
 # [ path.join [ project.attribute $(root-project) location ] ext $(1:L) ] ;
-#
+#
 # # Create the project itself, i.e. the attributes.
 # # All extensions are created in the "/ext" project space.
 # project /ext/$(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
 # local attributes = [ project.attributes $(__name__) ] ;
-#
+#
 # # Inherit from the root project of whomever is defining us.
 # project.inherit-attributes $(__name__) : $(root-project) ;
 # $(attributes).set parent-module : $(root-project) : exact ;
 # }
 #}
-
+
 
 class ProjectAttributes:
     """Class keeping all the attributes of a project.
@@ -735,26 +717,26 @@
     The standard attributes are 'id', "location", "project-root", "parent"
     "requirements", "default-build", "source-location" and "projects-to-build".
     """
-
+
     def __init__(self, manager, location, project_module):
         self.manager = manager
         self.location = location
         self.project_module = project_module
         self.attributes = {}
         self.usage_requirements = None
-
+
     def set(self, attribute, specification, exact=False):
         """Set the named attribute from the specification given by the user.
         The value actually set may be different."""
 
         if exact:
             self.__dict__[attribute] = specification
-
+
         elif attribute == "requirements":
             self.requirements = property_set.refine_from_user_input(
                 self.requirements, specification,
                 self.project_module, self.location)
-
+
         elif attribute == "usage-requirements":
             unconditional = []
             for p in specification:
@@ -765,7 +747,7 @@
                     unconditional.append(p)
 
             non_free = property.remove("free", unconditional)
- if non_free:
+ if non_free:
                 get_manager().errors()("usage-requirements %s have non-free properties %s" \
                                        % (specification, non_free))
 
@@ -780,16 +762,16 @@
                 new = property_set.create(t)
             self.__dict__["usage-requirements"] = new
 
-
+
         elif attribute == "default-build":
             self.__dict__["default-build"] = property_set.create(specification)
-
+
         elif attribute == "source-location":
             source_location = []
             for path in specification:
                 source_location.append(os.path.join(self.location, path))
             self.__dict__["source-location"] = source_location
-
+
         elif attribute == "build-dir":
             self.__dict__["build-dir"] = os.path.join(self.location, specification[0])
 
@@ -799,7 +781,7 @@
                 id = "/" + id
             self.manager.projects().register_id(id, self.project_module)
             self.__dict__["id"] = id
-
+
         elif not attribute in ["default-build", "location",
                                "source-location", "parent",
                                "projects-to-build", "project-root"]:
@@ -853,7 +835,7 @@
             bjam.import_rule(bjam_module, name, self.make_wrapper(callable), callable.bjam_signature)
         else:
             bjam.import_rule(bjam_module, name, self.make_wrapper(callable))
-
+
 
     def add_rule_for_type(self, type):
         rule_name = type.lower().replace("_", "-")
@@ -861,10 +843,10 @@
         def xpto (name, sources = [], requirements = [], default_build = [], usage_requirements = []):
             return self.manager_.targets().create_typed_target(
                 type, self.registry.current(), name[0], sources,
- requirements, default_build, usage_requirements)
+ requirements, default_build, usage_requirements)
 
         self.add_rule(rule_name, xpto)
-
+
     def add_rule(self, name, callable):
         self.rules[name] = callable
         self.all_names_.append(name)
@@ -890,7 +872,7 @@
                 self.manager_.errors().handle_stray_exception (e)
             except ExceptionWithUserContext, e:
                 e.report()
- finally:
+ finally:
             self.manager_.errors().pop_jamfile_context()
 
         return result
@@ -911,13 +893,13 @@
             for n in self.local_names:
                 if n != "import_":
                     setattr(m, n, getattr(self, n))
-
+
             for n in self.rules:
                 setattr(m, n, self.rules[n])
 
             return
-
- for n in self.local_names:
+
+ for n in self.local_names:
             # Using 'getattr' here gives us a bound method,
             # while using self.__dict__[r] would give unbound one.
             v = getattr(self, n)
@@ -926,7 +908,7 @@
                     n = "import"
                 else:
                     n = string.replace(n, "_", "-")
-
+
                 self._import_rule(project_module, n, v)
 
         for n in self.rules:
@@ -936,7 +918,7 @@
 
         jamfile_module = self.registry.current().project_module()
         attributes = self.registry.attributes(jamfile_module)
-
+
         id = None
         if args and args[0]:
             id = args[0][0]
@@ -951,7 +933,7 @@
                 attributes.set(a[0], a[1:], exact=0)
                 if a[0] == "build-dir":
                     explicit_build_dir = a[1]
-
+
         # If '--build-dir' is specified, change the build dir for the project.
         if self.registry.global_build_dir:
 
@@ -975,7 +957,7 @@
                     rid = id
                     if rid[0] == '/':
                         rid = rid[1:]
-
+
                     p = os.path.join(self.registry.global_build_dir, rid)
                     if explicit_build_dir:
                         p = os.path.join(p, explicit_build_dir)
@@ -1006,7 +988,7 @@
         # parameters as opposed to loading the project now.
         m = self.registry.current().project_module();
         self.registry.used_projects[m].append((id[0], where[0]))
-
+
     def build_project(self, dir):
         assert(isinstance(dir, list))
         jamfile_module = self.registry.current().project_module()
@@ -1040,7 +1022,7 @@
 "The patterns to 'glob-tree' may not include directory")
         return self.registry.glob_internal(self.registry.current(),
                                            wildcards, excludes, "glob_tree")
-
+
 
     def using(self, toolset, *args):
         # The module referred by 'using' can be placed in
@@ -1094,9 +1076,9 @@
 
             for n, l in zip(names_to_import, local_names):
                 self._import_rule(jamfile_module, l, m.__dict__[n])
-
+
         self.registry.set_current(saved)
-
+
     def conditional(self, condition, requirements):
         """Calculates conditional requirements for multiple requirements
         at once. This is a shorthand to be reduce duplication and to

Modified: branches/release/tools/build/v2/build/property-set.jam
==============================================================================
--- branches/release/tools/build/v2/build/property-set.jam (original)
+++ branches/release/tools/build/v2/build/property-set.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,7 +1,8 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import "class" : new ;
 import feature ;
@@ -37,7 +38,7 @@
     import property ;
     import property-set ;
     import set ;
-
+
     rule __init__ ( raw-properties * )
     {
         self.raw = $(raw-properties) ;
@@ -155,7 +156,8 @@
     {
         if ! $(self.expanded)
         {
- self.expanded = [ property-set.create [ feature.expand $(self.raw) ] ] ;
+ self.expanded = [ property-set.create [ feature.expand $(self.raw) ]
+ ] ;
         }
         return $(self.expanded) ;
     }
@@ -176,7 +178,8 @@
         if ! $(self.evaluated.$(context))
         {
             self.evaluated.$(context) = [ property-set.create
- [ property.evaluate-conditionals-in-context $(self.raw) : [ $(context).raw ] ] ] ;
+ [ property.evaluate-conditionals-in-context $(self.raw) : [
+ $(context).raw ] ] ] ;
         }
         return $(self.evaluated.$(context)) ;
     }
@@ -235,9 +238,8 @@
             }
             else
             {
- local p = [ as-path ] ;
- p = [ property-set.hash-maybe $(p) ] ;
-
+ local p = [ property-set.hash-maybe [ as-path ] ] ;
+
                 # A real ugly hack. Boost regression test system requires
                 # specific target paths, and it seems that changing it to handle
                 # other directory layout is really hard. For that reason, we
@@ -267,7 +269,8 @@
     {
         if ! $(self.added.$(ps))
         {
- self.added.$(ps) = [ property-set.create $(self.raw) [ $(ps).raw ] ] ;
+ self.added.$(ps) = [ property-set.create $(self.raw) [ $(ps).raw ] ]
+ ;
         }
         return $(self.added.$(ps)) ;
     }
@@ -294,7 +297,29 @@
         }
         return $($(feature)) ;
     }
-
+
+ # Returns true if the property-set contains all the
+ # specified properties.
+ #
+ rule contains-raw ( properties * )
+ {
+ if $(properties) in $(self.raw)
+ {
+ return true ;
+ }
+ }
+
+ # Returns true if the property-set has values for
+ # all the specified features
+ #
+ rule contains-features ( features * )
+ {
+ if $(features) in $(self.raw:G)
+ {
+ return true ;
+ }
+ }
+
     # private
 
     rule init-base ( )
@@ -324,9 +349,7 @@
     {
         for local p in $(self.raw)
         {
- local att = [ feature.attributes $(p:G) ] ;
-
- if dependency in $(att)
+ if dependency in [ feature.attributes $(p:G) ]
             {
                 self.dependency += $(p) ;
             }
@@ -342,6 +365,10 @@
     {
         for local p in $(self.raw)
         {
+ # TODO: Note that non-conditional properties may contain colon (':')
+ # characters as well, e.g. free or indirect properties. Indirect
+ # properties for example contain a full Jamfile path in their value
+ # which on Windows file systems contains ':' as the drive separator.
             if [ MATCH (:) : $(p:G=) ]
             {
                 self.conditional += $(p) ;
@@ -374,9 +401,18 @@
 }
 NATIVE_RULE property-set : create ;
 
+if [ HAS_NATIVE_RULE class_at_property-set : get : 1 ]
+{
+ NATIVE_RULE class_at_property-set : get ;
+}
+
+if [ HAS_NATIVE_RULE class_at_property-set : contains-features : 1 ]
+{
+ NATIVE_RULE class_at_property-set : contains-features ;
+}
 
 # Creates a new 'property-set' instance after checking that all properties are
-# valid and converting incidental properties into gristed form.
+# valid and converting implicit properties into gristed form.
 #
 rule create-with-validation ( raw-properties * )
 {
@@ -390,18 +426,10 @@
 #
 rule create-from-user-input ( raw-properties * : jamfile-module location )
 {
- local specification = [ property.translate-paths $(raw-properties)
- : $(location) ] ;
- specification = [ property.translate-indirect $(specification)
- : $(jamfile-module) ] ;
     local project-id = [ project.attribute $(jamfile-module) id ] ;
     project-id ?= [ path.root $(location) [ path.pwd ] ] ;
- specification = [ property.translate-dependencies
- $(specification) : $(project-id) : $(location) ] ;
- specification =
- [ property.expand-subfeatures-in-conditions $(specification) ] ;
- specification = [ property.make $(specification) ] ;
- return [ property-set.create $(specification) ] ;
+ return [ property-set.create [ property.translate $(raw-properties)
+ : $(project-id) : $(location) : $(jamfile-module) ] ] ;
 }
 
 
@@ -471,8 +499,9 @@
     return $(.empty) ;
 }
 
+
 if [ option.get hash : : yes ] = yes
-{
+{
     rule hash-maybe ( path ? )
     {
         path ?= "" ;
@@ -484,6 +513,5 @@
     rule hash-maybe ( path ? )
     {
         return $(path) ;
- }
+ }
 }
-

Modified: branches/release/tools/build/v2/build/property.jam
==============================================================================
--- branches/release/tools/build/v2/build/property.jam (original)
+++ branches/release/tools/build/v2/build/property.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,9 +2,9 @@
 # Copyright 2006 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
-import errors ;
 import feature ;
 import indirect ;
 import path ;
@@ -22,67 +22,28 @@
 rule refine ( properties * : requirements * )
 {
     local result ;
- local error ;
+ local unset ;
 
- # All the 'requirements' elements should be present in the result. Record
- # them so that we can handle 'properties'.
+ # Collect all non-free features in requirements
     for local r in $(requirements)
     {
         # Do not consider conditional requirements.
- if ! [ MATCH (:) : $(r:G=) ]
+ if ! [ MATCH (:) : $(r:G=) ] && ! free in [ feature.attributes $(r:G) ]
         {
- # Note: cannot use a local variable here, so use an ugly name.
- __require__$(r:G) = $(r:G=) ;
+ unset += $(r:G) ;
         }
     }
 
+ # Remove properties that are overridden by requirements
     for local p in $(properties)
     {
- if [ MATCH (:) : $(p:G=) ]
+ if [ MATCH (:) : $(p:G=) ] || ! $(p:G) in $(unset)
         {
- # Do not modify conditional properties.
             result += $(p) ;
         }
- else if free in [ feature.attributes $(p:G) ]
- {
- # Do not modify free properties.
- result += $(p) ;
- }
- else
- {
- local required-value = $(__require__$(p:G)) ;
- if $(required-value)
- {
- if $(p:G=) != $(required-value)
- {
- result += $(p:G)$(required-value) ;
- }
- else
- {
- result += $(p) ;
- }
- }
- else
- {
- result += $(p) ;
- }
- }
     }
 
- # Unset our ugly map.
- for local r in $(requirements)
- {
- __require__$(r:G) = ;
- }
-
- if $(error)
- {
- return $(error) ;
- }
- else
- {
- return [ sequence.unique $(result) $(requirements) ] ;
- }
+ return [ sequence.unique $(result) $(requirements) ] ;
 }
 
 
@@ -110,11 +71,11 @@
     for local p in $(conditionals)
     {
         # Separate condition and property.
- local s = [ MATCH (.*):(<.*) : $(p) ] ;
+ local s = [ MATCH ^(.*):(<.*) : $(p) ] ;
         # Split condition into individual properties.
         local condition = [ regex.split $(s[1]) "," ] ;
         # Evaluate condition.
- if ! [ MATCH (!).* : $(condition:G=) ]
+ if ! [ MATCH ^(!).* : $(condition:G=) ]
         {
             # Only positive checks
             if $(condition) in $(context)
@@ -129,7 +90,7 @@
             while $(condition)
             {
                 local c = $(condition[1]) ;
- local m = [ MATCH !(.*) : $(c) ] ;
+ local m = [ MATCH ^!(.*) : $(c) ] ;
                 if $(m)
                 {
                     local p = $(m:G=$(c:G)) ;
@@ -137,23 +98,23 @@
                     {
                         fail = true ;
                         c = ;
- }
- }
+ }
+ }
                 else
                 {
                     if ! $(c) in $(context)
                     {
                         fail = true ;
                         c = ;
- }
+ }
                 }
                 condition = $(condition[2-]) ;
             }
             if ! $(fail)
             {
                 result += $(s[2]) ;
- }
- }
+ }
+ }
     }
     return $(result) ;
 }
@@ -164,7 +125,7 @@
     local result ;
     for local p in $(properties)
     {
- local s = [ MATCH (.*):(<.*) : $(p) ] ;
+ local s = [ MATCH ^(.*):(<.*) : $(p) ] ;
         if ! $(s)
         {
             result += $(p) ;
@@ -325,6 +286,7 @@
     }
     if $(msg)
     {
+ import errors ;
         errors.error "Invalid property "'$(property:J=" ")'": "$(msg:J=" "). ;
     }
 }
@@ -367,6 +329,7 @@
         }
         else
         {
+ import errors ;
             errors.error "'$(e)' is not a valid property specification" ;
         }
     }
@@ -457,13 +420,149 @@
 #
 rule split-conditional ( property )
 {
- local m = [ MATCH "(.+):<(.+)" : $(property) ] ;
- if $(m)
+ return [ MATCH "^(.+):(<.+)" : $(property) ] ;
+}
+
+
+rule translate-path-value ( value : path )
+{
+ local t ;
+ for local v in [ regex.split $(value) "&&" ]
+ {
+ t += [ path.root [ path.make $(v) ] $(path) ] ;
+ }
+ return $(t:TJ="&&") ;
+}
+
+rule translate-dependency-value ( value : project-id : project-location )
+{
+ local split-target = [ regex.match ^(.*)//(.*) : $(value) ] ;
+ if $(split-target)
+ {
+ local rooted = [ path.root [ path.make $(split-target[1]) ]
+ [ path.root $(project-location) [ path.pwd ] ] ] ;
+ return $(rooted)//$(split-target[2]) ;
+ }
+ else if [ path.is-rooted $(value) ]
+ {
+ return $(value) ;
+ }
+ else
     {
- return $(m[1]) <$(m[2]) ;
+ return $(project-id)//$(value) ;
     }
 }
 
+rule translate-indirect-value ( rulename : context-module )
+{
+ if [ MATCH "^([^%]*)%([^%]+)$" : $(rulename) ]
+ {
+ # Rule is already in the 'indirect-rule' format.
+ return @$(rulename) ;
+ }
+ else
+ {
+ local v ;
+ if ! [ MATCH "([.])" : $(rulename) ]
+ {
+ # This is an unqualified rule name. The user might want to
+ # set flags on this rule name and toolset.flag
+ # auto-qualifies it. Need to do the same here so flag
+ # setting works. We can arrange for toolset.flag to *not*
+ # auto-qualify the argument but then two rules defined in
+ # two Jamfiles would conflict.
+ rulename = $(context-module).$(rulename) ;
+ }
+ v = [ indirect.make $(rulename) : $(context-module) ] ;
+ return @$(v) ;
+ }
+
+}
+
+# Equivalent to a calling all of:
+# translate-path
+# translate-indirect
+# translate-dependency
+# expand-subfeatures-in-conditions
+# make
+#
+rule translate ( properties * : project-id : project-location : context-module )
+{
+ local result ;
+ for local p in $(properties)
+ {
+ local split = [ split-conditional $(p) ] ;
+ local condition property ;
+
+ if $(split)
+ {
+ condition = $(split[1]) ;
+ property = $(split[2]) ;
+
+ local e ;
+ for local c in [ regex.split $(condition) "," ]
+ {
+ e += [ feature.expand-subfeatures $(c) : true ] ;
+ }
+
+ condition = $(e:J=,): ;
+ }
+ else
+ {
+ property = $(p) ;
+ }
+
+ local feature = $(property:G) ;
+ if ! $(feature)
+ {
+ if [ feature.is-implicit-value $(property) ]
+ {
+ feature = [ feature.implied-feature $(property) ] ;
+ result += $(condition:E=)$(feature)$(property) ;
+ }
+ else
+ {
+ import errors ;
+ errors.error "'$(e)' is not a valid property specification" ;
+ }
+ } else {
+ local attributes = [ feature.attributes $(feature) ] ;
+ local value ;
+ # Only free features should be translated
+ if free in $(attributes)
+ {
+ if path in $(attributes)
+ {
+ value = [ translate-path-value $(property:G=) : $(project-location) ] ;
+ result += $(condition:E=)$(feature)$(value) ;
+ }
+ else if dependency in $(attributes)
+ {
+ value = [ translate-dependency-value $(property:G=) : $(project-id) : $(project-location) ] ;
+ result += $(condition:E=)$(feature)$(value) ;
+ }
+ else
+ {
+ local m = [ MATCH ^@(.+) : $(property:G=) ] ;
+ if $(m)
+ {
+ value = [ translate-indirect-value $(m) : $(context-module) ] ;
+ result += $(condition:E=)$(feature)$(value) ;
+ }
+ else
+ {
+ result += $(condition:E=)$(property) ;
+ }
+ }
+ }
+ else
+ {
+ result += $(condition:E=)$(property) ;
+ }
+ }
+ }
+ return $(result) ;
+}
 
 # Interpret all path properties in 'properties' as relative to 'path'. The
 # property values are assumed to be in system-specific form, and will be
@@ -524,7 +623,7 @@
             }
             else
             {
- if ! [ MATCH ".*([.]).*" : $(m) ]
+ if ! [ MATCH "([.])" : $(m) ]
                 {
                     # This is an unqualified rule name. The user might want to
                     # set flags on this rule name and toolset.flag
@@ -568,7 +667,7 @@
         }
         if dependency in [ feature.attributes $(p:G) ]
         {
- local split-target = [ regex.match (.*)//(.*) : $(p:G=) ] ;
+ local split-target = [ regex.match ^(.*)//(.*) : $(p:G=) ] ;
             if $(split-target)
             {
                 local rooted = [ path.root [ path.make $(split-target[1]) ]
@@ -597,7 +696,6 @@
 #
 class property-map
 {
- import errors ;
     import numbers ;
     import sequence ;
 
@@ -608,11 +706,10 @@
 
     # Associate 'value' with 'properties'.
     #
- rule insert ( properties + : value )
+ rule insert ( properties * : value )
     {
- self.all-flags += $(self.next-flag) ;
- self.properties.$(self.next-flag) = $(properties) ;
- self.value.$(self.next-flag) = $(value) ;
+ self.all-flags += self.$(self.next-flag) ;
+ self.$(self.next-flag) = $(value) $(properties) ;
 
         self.next-flag = [ numbers.increment $(self.next-flag) ] ;
     }
@@ -621,37 +718,57 @@
     # more than one subset has a value assigned to it, returns the value for the
     # longest subset, if it is unique.
     #
- rule find ( properties + )
+ rule find ( property-set )
     {
- return [ find-replace $(properties) ] ;
+ # First find all matches.
+ local matches ;
+ local match-ranks ;
+ for local i in $(self.all-flags)
+ {
+ local list = $($(i)) ;
+ if [ $(property-set).contains-raw $(list[2-]) ]
+ {
+ matches += $(list[1]) ;
+ match-ranks += [ sequence.length $(list) ] ;
+ }
+ }
+ local best = [ sequence.select-highest-ranked $(matches)
+ : $(match-ranks) ] ;
+ if $(best[2])
+ {
+ import errors : error : errors.error ;
+ errors.error "Ambiguous key $(properties:J= :E=)" ;
+ }
+ return $(best) ;
     }
 
     # Returns the value associated with 'properties'. If 'value' parameter is
     # given, replaces the found value.
     #
- rule find-replace ( properties + : value ? )
+ rule find-replace ( properties * : value ? )
     {
         # First find all matches.
         local matches ;
         local match-ranks ;
         for local i in $(self.all-flags)
         {
- if $(self.properties.$(i)) in $(properties)
+ if $($(i)[2-]) in $(properties)
             {
                 matches += $(i) ;
- match-ranks += [ sequence.length $(self.properties.$(i)) ] ;
+ match-ranks += [ sequence.length $($(i)) ] ;
             }
         }
         local best = [ sequence.select-highest-ranked $(matches)
             : $(match-ranks) ] ;
         if $(best[2])
- {
+ {
+ import errors : error : errors.error ;
             errors.error "Ambiguous key $(properties:J= :E=)" ;
         }
- local original = $(self.value.$(best)) ;
+ local original = $($(best)[1]) ;
         if $(value)
         {
- self.value.$(best) = $(value) ;
+ $(best) = $(value) $($(best)[2-]) ;
         }
         return $(original) ;
     }
@@ -744,7 +861,7 @@
 
     try ;
         validate value : $(test-space) ;
- catch "value" is not a value of an implicit feature ;
+ catch \"value\" is not an implicit feature value ;
 
     assert.result-set-equal <rtti>on
         : remove free implicit : <toolset>gcc <define>foo <rtti>on : $(test-space) ;
@@ -766,12 +883,12 @@
     $(pm).insert <toolset>gcc <os>NT : obj ;
     $(pm).insert <toolset>gcc <os>CYGWIN : obj ;
 
- assert.equal o : [ $(pm).find <toolset>gcc ] ;
+ assert.equal o : [ $(pm).find-replace <toolset>gcc ] ;
 
- assert.equal obj : [ $(pm).find <toolset>gcc <os>NT ] ;
+ assert.equal obj : [ $(pm).find-replace <toolset>gcc <os>NT ] ;
 
     try ;
- $(pm).find <toolset>gcc <os>NT <os>CYGWIN ;
+ $(pm).find-replace <toolset>gcc <os>NT <os>CYGWIN ;
     catch "Ambiguous key <toolset>gcc <os>NT <os>CYGWIN" ;
 
     # Test ordinary properties.

Modified: branches/release/tools/build/v2/build/property_set.py
==============================================================================
--- branches/release/tools/build/v2/build/property_set.py (original)
+++ branches/release/tools/build/v2/build/property_set.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -25,7 +25,7 @@
     # A cache of property sets
     # TODO: use a map of weak refs?
     __cache = {}
-
+
 reset ()
 
 
@@ -36,13 +36,13 @@
     # FIXME: propagate to callers.
     if len(raw_properties) > 0 and isinstance(raw_properties[0], property.Property):
         x = raw_properties
- else:
+ else:
         x = [property.create_from_string(ps) for ps in raw_properties]
     x.sort()
     x = unique (x)
 
     # FIXME: can we do better, e.g. by directly computing
- # has value of the list?
+ # hash value of the list?
     key = tuple(x)
 
     if not __cache.has_key (key):
@@ -52,12 +52,12 @@
 
 def create_with_validation (raw_properties):
     """ Creates new 'PropertySet' instances after checking
- that all properties are valid and converting incidental
+ that all properties are valid and converting implicit
         properties into gristed form.
     """
     properties = [property.create_from_string(s) for s in raw_properties]
     property.validate(properties)
-
+
     return create(properties)
 
 def empty ():
@@ -75,7 +75,7 @@
 
     project_id = get_manager().projects().attributeDefault(jamfile_module, 'id', None)
     if not project_id:
- project_id = os.path.abspath(location)
+ project_id = os.path.abspath(location)
     properties = property.translate_dependencies(properties, project_id, location)
     properties = property.expand_subfeatures_in_conditions(properties)
     return create(properties)
@@ -97,7 +97,7 @@
     if not specification:
         return parent_requirements
 
-
+
     add_requirements = []
     remove_requirements = []
 
@@ -106,23 +106,23 @@
             remove_requirements.append(r[1:])
         else:
             add_requirements.append(r)
-
+
     if remove_requirements:
         # Need to create property set, so that path features
         # and indirect features are translated just like they
         # are in project requirements.
         ps = create_from_user_input(remove_requirements,
                                     jamfile_module, location)
-
+
         parent_requirements = create(difference(parent_requirements.all(),
                                                 ps.all()))
         specification = add_requirements
 
     requirements = create_from_user_input(specification,
                                           jamfile_module, location)
-
+
     return parent_requirements.refine(requirements)
-
+
 class PropertySet:
     """ Class for storing a set of properties.
         - there's 1<->1 correspondence between identity and value. No
@@ -152,7 +152,7 @@
         self.all_ = properties
         self.all_raw_ = raw_properties
         self.all_set_ = set(properties)
-
+
         self.incidental_ = []
         self.free_ = []
         self.base_ = []
@@ -162,10 +162,10 @@
         self.non_conditional_ = []
         self.propagated_ = []
         self.link_incompatible = []
-
+
         # A cache of refined properties.
         self.refined_ = {}
-
+
         # A cache of property sets created by adding properties to this one.
         self.added_ = {}
 
@@ -183,24 +183,24 @@
 
         # Cache for the property set containing propagated properties.
         self.propagated_ps_ = None
-
+
         # A map of features to its values.
         self.feature_map_ = None
-
+
         # A tuple (target path, is relative to build directory)
         self.target_path_ = None
-
+
         self.as_path_ = None
-
+
         # A cache for already evaluated sets.
         self.evaluated_ = {}
-
+
         for p in raw_properties:
             if not get_grist (p):
                 raise BaseException ("Invalid property: '%s'" % p)
-
+
             att = feature.attributes (get_grist (p))
-
+
             if 'propagated' in att:
                 self.propagated_.append (p)
 
@@ -227,11 +227,11 @@
                 self.dependency_.append (p)
             else:
                 self.non_dependency_.append (p)
-
+
 
     def all(self):
         return self.all_
-
+
     def raw (self):
         """ Returns the list of stored properties.
         """
@@ -239,12 +239,12 @@
 
     def __str__(self):
         return ' '.join(str(p) for p in self.all_)
-
+
     def base (self):
         """ Returns properties that are neither incidental nor free.
         """
         return self.base_
-
+
     def free (self):
         """ Returns free properties which are not dependency properties.
         """
@@ -257,27 +257,27 @@
         """ Returns dependency properties.
         """
         return self.dependency_
-
+
     def non_dependency (self):
         """ Returns properties that are not dependencies.
         """
         return self.non_dependency_
-
+
     def conditional (self):
         """ Returns conditional properties.
         """
         return self.conditional_
-
+
     def non_conditional (self):
         """ Returns properties that are not conditional.
         """
         return self.non_conditional_
-
+
     def incidental (self):
         """ Returns incidental properties.
         """
         return self.incidental_
-
+
     def refine (self, requirements):
         """ Refines this set's properties using the requirements passed as an argument.
         """
@@ -339,10 +339,10 @@
 
             # trim redundancy
             properties = feature.minimize(self.base_)
-
+
             # sort according to path_order
             properties.sort (path_order)
-
+
             components = []
             for p in properties:
                 if p.feature().implicit():
@@ -355,12 +355,12 @@
         return self.as_path_
 
     def target_path (self):
- """ Computes the target path that should be used for
+ """ Computes the target path that should be used for
             target with these properties.
             Returns a tuple of
               - the computed path
               - if the path is relative to build directory, a value of
- 'true'.
+ 'true'.
         """
         if not self.target_path_:
             # The <location> feature can be used to explicitly
@@ -372,18 +372,18 @@
 
             else:
                 p = self.as_path ()
-
+
                 # Really, an ugly hack. Boost regression test system requires
                 # specific target paths, and it seems that changing it to handle
                 # other directory layout is really hard. For that reason,
                 # we teach V2 to do the things regression system requires.
                 # The value o '<location-prefix>' is predended to the path.
                 prefix = self.get ('<location-prefix>')
-
+
                 if prefix:
                     if len (prefix) > 1:
                         raise AlreadyDefined ("Two <location-prefix> properties specified: '%s'" % prefix)
-
+
                     computed = os.path.join(prefix[0], p)
 
                 else:
@@ -397,7 +397,7 @@
             self.target_path_ = (computed, is_relative)
 
         return self.target_path_
-
+
     def add (self, ps):
         """ Creates a new property set containing the properties in this one,
             plus the ones of the property set passed as argument.
@@ -405,14 +405,14 @@
         if not self.added_.has_key(ps):
             self.added_[ps] = create(self.all_ + ps.all())
         return self.added_[ps]
-
+
     def add_raw (self, properties):
         """ Creates a new property set containing the properties in this one,
             plus the ones passed as argument.
         """
         return self.add (create (properties))
 
-
+
     def get (self, feature):
         """ Returns all values of 'feature'.
         """
@@ -420,7 +420,7 @@
             feature = feature[0]
         if not isinstance(feature, b2.build.feature.Feature):
             feature = b2.build.feature.get(feature)
-
+
         if not self.feature_map_:
             self.feature_map_ = {}
 
@@ -428,7 +428,7 @@
                 if not self.feature_map_.has_key(v.feature()):
                     self.feature_map_[v.feature()] = []
                 self.feature_map_[v.feature()].append(v.value())
-
+
         return self.feature_map_.get(feature, [])
 
     @cached
@@ -438,12 +438,12 @@
         if not isinstance(feature, b2.build.feature.Feature):
             feature = b2.build.feature.get(feature)
 
- result = []
+ result = []
         for p in self.all_:
             if p.feature() == feature:
                 result.append(p)
         return result
-
+
     def __contains__(self, item):
         return item in self.all_set_
-
+

Modified: branches/release/tools/build/v2/build/readme.txt
==============================================================================
--- branches/release/tools/build/v2/build/readme.txt (original)
+++ branches/release/tools/build/v2/build/readme.txt 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,13 +1,11 @@
-Copyright 2001, 2002 Dave Abrahams
-Copyright 2002 Vladimir Prus
-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)
+Copyright 2001, 2002 Dave Abrahams
+Copyright 2002 Vladimir Prus
+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)
 
 Development code for new build system. To run unit tests for jam code, execute:
 
   bjam --debug --build-system=test
 
 Comprehensive tests require Python. See ../test/readme.txt
-
-
-

Modified: branches/release/tools/build/v2/build/scanner.jam
==============================================================================
--- branches/release/tools/build/v2/build/scanner.jam (original)
+++ branches/release/tools/build/v2/build/scanner.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,78 +1,85 @@
-# Copyright 2003 Dave Abrahams
-# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
-# 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)
-
-# Implements scanners: objects that compute implicit dependencies for
-# files, such as includes in C++.
-#
-# Scanner has a regular expression used to find dependencies, some
-# data needed to interpret those dependencies (for example, include
-# paths), and a code which actually established needed relationship
-# between actual jam targets.
-#
-# Scanner objects are created by actions, when they try to actualize
-# virtual targets, passed to 'virtual-target.actualize' method and are
-# then associated with actual targets. It is possible to use
-# several scanners for a virtual-target. For example, a single source
-# might be used by to compile actions, with different include paths.
-# In this case, two different actual targets will be created, each
-# having scanner of its own.
-#
-# Typically, scanners are created from target type and action's
-# properties, using the rule 'get' in this module. Directly creating
-# scanners is not recommended, because it might create many equvivalent
-# but different instances, and lead in unneeded duplication of
-# actual targets. However, actions can also create scanners in a special
-# way, instead of relying on just target type.
+# Copyright 2003 Dave Abrahams
+# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
+# 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)
+
+# Implements scanners: objects computing implicit dependencies for files, such
+# as includes in C++.
+#
+# A scanner has a regular expression used to find the dependencies, some data
+# needed to interpret those dependencies (e.g., include paths), and code which
+# establishing needed relationships between actual jam targets.
+#
+# Scanner objects are created by actions when they try to actualize virtual
+# targets, passed to the virtual-target.actualize() method and are then
+# associated with actual targets. It is possible to use several scanners for a
+# single virtual-target. For example, a single source file might be compiled
+# twice - each time using a different include path. In this case, two separate
+# actual targets will be created, each having a scanner of its own.
+#
+# Typically, scanners are created from target type and the action's properties,
+# using the rule 'get' in this module. Directly creating scanners is not
+# recommended, as it might create multiple equvivalent but different instances,
+# and lead to unnecessary actual target duplication. However, actions can also
+# create scanners in a special way, instead of relying on just the target type.
 
 import "class" : new ;
-import property virtual-target property-set ;
-import errors : error ;
+import property ;
+import property-set ;
+import virtual-target ;
 
-# Base scanner class.
-class scanner
+# Base scanner class.
+#
+class scanner
 {
     rule __init__ ( )
     {
     }
-
- # Returns a pattern to use for scanning
+
+ # Returns a pattern to use for scanning.
+ #
     rule pattern ( )
     {
- error "method must be overriden" ;
+ import errors : error : errors.error ;
+ errors.error "method must be overriden" ;
     }
 
- # Establish necessary relationship between targets,
- # given actual target beeing scanned, and a list of
- # pattern matches in that file.
+ # Establish necessary relationship between targets, given an actual target
+ # beeing scanned and a list of pattern matches in that file.
+ #
     rule process ( target : matches * )
     {
- error "method must be overriden" ;
- }
+ import errors : error : errors.error ;
+ errors.error "method must be overriden" ;
+ }
 }
 
-# Registers a new generator class, specifying a set of
-# properties relevant to this scanner. Ctor for that class
-# should have one parameter: list of properties.
+
+# Registers a new generator class, specifying a set of properties relevant to
+# this scanner. Constructor for that class should have one parameter: a list of
+# properties.
+#
 rule register ( scanner-class : relevant-properties * )
 {
     .registered += $(scanner-class) ;
     .relevant-properties.$(scanner-class) = $(relevant-properties) ;
 }
 
-# Common scanner class, which can be used when there's only one
-# kind of includes (unlike C, where "" and <> includes have different
-# search paths).
-class common-scanner : scanner
+
+# Common scanner class, usable when there is only one kind of includes (unlike
+# C, where "" and <> includes have different search paths).
+#
+class common-scanner : scanner
 {
     import scanner ;
+
     rule __init__ ( includes * )
     {
         scanner.__init__ ;
         self.includes = $(includes) ;
     }
-
+
     rule process ( target : matches * : binding )
     {
         local target_path = [ NORMALIZE_PATH $(binding:D) ] ;
@@ -81,55 +88,59 @@
         INCLUDES $(target) : $(matches) ;
         SEARCH on $(matches) = $(target_path) $(self.includes:G=) ;
         ISFILE $(matches) ;
-
- scanner.propagate $(__name__) : $(matches) : $(target) ;
+
+ scanner.propagate $(__name__) : $(matches) : $(target) ;
     }
 }
 
 
-# Returns an instance of previously registered scanner,
-# with the specified properties.
-rule get ( scanner-class : property-set )
+# Returns an instance of a previously registered scanner, with the specified
+# properties.
+#
+rule get ( scanner-class : property-set )
 {
     if ! $(scanner-class) in $(.registered)
     {
- error "attempt to get unregisted scanner" ;
+ import errors ;
+ errors.error "attempt to get an unregisted scanner" ;
     }
-
+
     local r = $(.rv-cache.$(property-set)) ;
     if ! $(r)
     {
- r = [ property-set.create
+ r = [ property-set.create
             [ property.select $(.relevant-properties.$(scanner-class)) :
- [ $(property-set).raw ] ] ] ;
+ [ $(property-set).raw ] ] ] ;
         .rv-cache.$(property-set) = $(r) ;
     }
-
+
     if ! $(scanner.$(scanner-class).$(r:J=-))
     {
- scanner.$(scanner-class).$(r:J=-) = [ new $(scanner-class) [ $(r).raw ] ] ;
+ local s = [ new $(scanner-class) [ $(r).raw ] ] ;
+ scanner.$(scanner-class).$(r:J=-) = $(s) ;
     }
- return $(scanner.$(scanner-class).$(r:J=-)) ;
+ return $(scanner.$(scanner-class).$(r:J=-)) ;
 }
 
 
-# Installs the specified scanner on actual target 'target'.
-rule install ( scanner : target
- vtarget # virtual target from which 'target' was actualized
-)
+# Installs the specified scanner on the actual target 'target'.
+#
+rule install ( scanner : target )
 {
     HDRSCAN on $(target) = [ $(scanner).pattern ] ;
     SCANNER on $(target) = $(scanner) ;
     HDRRULE on $(target) = scanner.hdrrule ;
-
- # scanner reflects difference in properties affecting
- # binding of 'target', which will be known when processing
- # includes for it, will give information on how to
- # interpret quoted includes.
+
+ # Scanner reflects differences in properties affecting binding of 'target',
+ # which will be known when processing includes for it, and give information
+ # on how to interpret different include types (e.g. quoted vs. those in
+ # angle brackets in C files).
     HDRGRIST on $(target) = $(scanner) ;
 }
 
-# Propagate scanner setting from 'including-target' to 'targets'.
+
+# Propagate scanner settings from 'including-target' to 'targets'.
+#
 rule propagate ( scanner : targets * : including-target )
 {
     HDRSCAN on $(targets) = [ on $(including-target) return $(HDRSCAN) ] ;
@@ -144,10 +155,9 @@
     local scanner = [ on $(target) return $(SCANNER) ] ;
     $(scanner).process $(target) : $(matches) : $(binding) ;
 }
-# hdrrule must be available at global scope so that it can be invoked
-# by header scanning
-IMPORT scanner : hdrrule : : scanner.hdrrule ;
-
-
 
 
+# hdrrule must be available at global scope so it can be invoked by header
+# scanning.
+#
+IMPORT scanner : hdrrule : : scanner.hdrrule ;

Modified: branches/release/tools/build/v2/build/targets.jam
==============================================================================
--- branches/release/tools/build/v2/build/targets.jam (original)
+++ branches/release/tools/build/v2/build/targets.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,9 +1,8 @@
 # Copyright Vladimir Prus 2002.
 # Copyright Rene Rivera 2006.
-#
 # 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 accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Supports 'abstract' targets, which are targets explicitly defined in a
 # Jamfile.
@@ -23,53 +22,52 @@
 # create an instance of that class and add it to the list of alternatives for
 # the main target.
 #
-# Rules supplied by the build system will use only targets derived from
+# Rules supplied by the build system will use only targets derived from the
 # 'basic-target' class, which will provide some default behaviour. There will be
 # different classes derived from it such as 'make-target', created by the 'make'
 # rule, and 'typed-target', created by rules such as 'exe' and 'lib'.
-
 #
-# +------------------------+
-# |abstract-target |
-# +========================+
-# |name |
-# |project |
-# | |
-# |generate(properties) = 0|
-# +-----------+------------+
-# |
-# ^
-# / \
-# +-+-+
-# |
-# |
-# +------------------------+------+------------------------------+
-# | | |
-# | | |
-# +----------+-----------+ +------+------+ +------+-------+
-# | project-target | | main-target | | basic-target |
-# +======================+ 1 * +=============+ alternatives +==============+
-# | generate(properties) |o-----------+ generate |<>------------->| generate |
-# | main-target | +-------------+ | construct = 0|
-# +----------------------+ +--------------+
-# |
-# ^
-# / \
-# +-+-+
-# |
-# |
-# ...--+----------------+------------------+----------------+---+
-# | | | |
-# | | | |
-# ... ---+-----+ +------+-------+ +------+------+ +--------+-----+
-# | | typed-target | | make-target | | stage-target |
-# . +==============+ +=============+ +==============+
-# . | construct | | construct | | construct |
-# +--------------+ +-------------+ +--------------+
+# +--------------------------+
+# | abstract-target |
+# +==========================+
+# | name |
+# | project |
+# | |
+# | generate(properties) = 0 |
+# +-------------+------------+
+# |
+# ^
+# / \
+# +-+-+
+# |
+# |
+# +------------------+-----+-------------------------------+
+# | | |
+# | | |
+# +-----------+----------+ +------+------+ +-------+------+
+# | project-target | | main-target | | basic-target |
+# +======================+ 1 * +=============+ alternatives +==============+
+# | generate(properties) |o-----+ generate |<>------------->| generate |
+# | main-target | +-------------+ | construct = 0|
+# +----------------------+ +-------+------+
+# |
+# ^
+# / \
+# +-+-+
+# |
+# |
+# ...--+-----------------+-----------------+------------------+
+# | | | |
+# | | | |
+# ... ---+-----+ +-------+------+ +------+------+ +-------+------+
+# | | typed-target | | make-target | | stage-target |
+# . +==============+ +=============+ +==============+
+# . | construct | | construct | | construct |
+# +--------------+ +-------------+ +--------------+
 
 import assert ;
+import build-request ;
 import "class" : new ;
-import errors ;
 import feature ;
 import indirect ;
 import path ;
@@ -78,17 +76,16 @@
 import sequence ;
 import set ;
 import toolset ;
-import build-request ;
 
 
 # Base class for all abstract targets.
 #
 class abstract-target
 {
- import project ;
     import assert ;
     import "class" ;
     import errors ;
+ import project ;
 
     rule __init__ ( name # Name of the target in Jamfile.
         : project-target # The project target to which this one belongs.
@@ -195,7 +192,6 @@
     import set ;
     import sequence ;
     import "class" : new ;
- import errors ;
 
     rule __init__ ( name : project-module parent-project ?
         : requirements * : default-build * )
@@ -213,8 +209,8 @@
         }
     }
 
- # This is needed only by the 'make' rule. Need to find the way to make
- # 'make' work without this method.
+ # This is needed only by the 'make' rule. Need to find a way to make 'make'
+ # work without this method.
     #
     rule project-module ( )
     {
@@ -233,8 +229,25 @@
             self.build-dir = [ get build-dir ] ;
             if ! $(self.build-dir)
             {
- self.build-dir = [ path.join [ $(self.project).get location ]
- bin ] ;
+ local location = [ $(self.project).get location ] ;
+ if $(location)
+ {
+ self.build-dir = [ path.join $(location) bin ] ;
+ }
+ else
+ {
+ local id = [ get id ] ;
+ if $(id)
+ {
+ local rid = [ MATCH ^/(.*) : $(id) ] ;
+ self.build-dir = [ path.join [ project.standalone-build-dir ] $(rid) ] ;
+ }
+ else
+ {
+ errors.error "Could not create build-dir for standalone project $(self.project-module:E=)."
+ : "Missing project id" ;
+ }
+ }
             }
         }
         return $(self.build-dir) ;
@@ -246,7 +259,8 @@
     {
         if [ modules.peek : .debug-building ]
         {
- ECHO [ targets.indent ] "building project" [ name ] " ('$(__name__)') with" [ $(property-set).raw ] ;
+ ECHO [ targets.indent ] "building project" [ name ]
+ " ('$(__name__)') with" [ $(property-set).raw ] ;
             targets.increase-indent ;
         }
 
@@ -303,7 +317,7 @@
         # before main target instances are created.
         self.explicit-targets += $(target-name) ;
     }
-
+
     rule mark-target-as-always ( target-name * )
     {
         # Record the name of the target, not instance, since this rule is called
@@ -317,6 +331,7 @@
     {
         if $(self.built-main-targets)
         {
+ import errors : error : errors.error ;
             errors.error add-alternative called when main targets are already
                 created. : in project [ full-name ] ;
         }
@@ -357,7 +372,7 @@
         local result ;
         local current-location = [ get location ] ;
 
- local split = [ MATCH (.*)//(.*) : $(id) ] ;
+ local split = [ MATCH ^(.*)//(.*)$ : $(id) ] ;
         local project-part = $(split[1]) ;
         local target-part = $(split[2]) ;
 
@@ -374,11 +389,17 @@
             }
             else
             {
- # TODO: This extra error message will not get displayed most
- # likely due to some buggy refactoring. Refactor the code so the
- # message gets diplayed again.
- extra-error-message = error: could not find project
+ extra-error-message = could not resolve project reference
                     '$(project-part)' ;
+ if ! [ path.is-rooted $(project-part) ]
+ {
+ local rooted = [ path.root $(project-part) / ] ;
+ if [ project.is-registered-id $(rooted) ]
+ {
+ extra-error-message += - possibly missing a leading
+ slash ('/') character. ;
+ }
+ }
             }
         }
         else
@@ -395,7 +416,7 @@
             # Jamfile and a file named 'test' on the disk. We need the target to
             # override the file.
             result = [ main-target $(id) ] ;
-
+
             # Interpret id as an existing file reference.
             if ! $(result)
             {
@@ -419,7 +440,7 @@
             }
         }
 
- return $(result) ;
+ return $(result:E="") $(extra-error-message) ;
     }
 
     # Find and return the target with the specified id, treated relative to
@@ -430,9 +451,12 @@
     rule find ( id : no-error ? )
     {
         local v = $(.id.$(id)) ;
+ local extra-error-message ;
         if ! $(v)
         {
- v = [ find-really $(id) ] ;
+ local r = [ find-really $(id) ] ;
+ v = $(r[1]) ;
+ extra-error-message = $(r[2-]) ;
             if ! $(v)
             {
                 v = none ;
@@ -444,18 +468,15 @@
         {
             return $(v) ;
         }
- else
+ else if ! $(no-error)
         {
- if ! $(no-error)
- {
- local current-location = [ get location ] ;
- ECHO "error: Unable to find file or target named" ;
- ECHO "error: '$(id)'" ;
- ECHO "error: referred from project at" ;
- ECHO "error: '$(current-location)'" ;
- ECHO $(extra-error-message) ;
- EXIT ;
- }
+ local current-location = [ get location ] ;
+ import errors : user-error : errors.user-error ;
+ errors.user-error Unable to find file or target named
+ : " " '$(id)'
+ : referred to from project at
+ : " " '$(current-location)'
+ : $(extra-error-message) ;
         }
     }
 
@@ -473,11 +494,11 @@
                 self.main-targets += $(t) ;
                 target = $(self.main-target.$(name)) ;
             }
-
+
             if $(name) in $(self.always-targets)
             {
                 $(a).always ;
- }
+ }
 
             $(target).add-alternative $(a) ;
         }
@@ -500,13 +521,13 @@
                 local l = $(self.location) ;
                 if ! $(l)
                 {
- # Project corresponding to config files do not have
- # 'location' attribute, but do have source location.
- # It might be more reasonable to make every project have
- # a location and use some other approach to prevent buildable
- # targets in config files, but that's for later.
+ # Project corresponding to config files do not have
+ # 'location' attribute, but do have source location. It
+ # might be more reasonable to make every project have a
+ # location and use some other approach to prevent buildable
+ # targets in config files, but that has been left for later.
                     l = [ get source-location ] ;
- }
+ }
                 v = [ path.root [ path.make $(v) ] $(l) ] ;
                 # Now make the value absolute path.
                 v = [ path.root $(v) [ path.pwd ] ] ;
@@ -531,8 +552,8 @@
         {
             # No need to pass the type. Path constants were converted to
             # absolute paths already by parent.
- add-constant $(c)
- : [ modules.peek $(parent) : self.constant.$(c) ] ;
+ add-constant $(c) : [ modules.peek $(parent) : self.constant.$(c) ]
+ ;
         }
 
         # Import rules from parent.
@@ -543,7 +564,8 @@
         local user-rules = [ set.difference
             [ RULENAMES $(parent-module) ] :
             [ RULENAMES project-rules ] ] ;
- IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules) ;
+ IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules)
+ ;
         EXPORT $(this-module) : $(user-rules) ;
     }
 }
@@ -561,6 +583,7 @@
             names += [ $(t).full-name ] ;
         }
 
+ import errors ;
         errors.error "Recursion in main target references"
           : "the following target are being built currently:"
           : $(names) ;
@@ -580,7 +603,6 @@
 class main-target : abstract-target
 {
     import assert ;
- import errors ;
     import feature ;
     import print ;
     import property-set ;
@@ -598,10 +620,12 @@
         local d = [ $(target).default-build ] ;
         if $(self.alternatives) && ( $(self.default-build) != $(d) )
         {
+ import errors : error : errors.error ;
             errors.error "default build must be identical in all alternatives"
- : "main target is" [ full-name ]
- : "with" [ $(d).raw ]
- : "differing from previous default build" [ $(self.default-build).raw ] ;
+ : "main target is" [ full-name ]
+ : "with" [ $(d).raw ]
+ : "differing from previous default build"
+ [ $(self.default-build).raw ] ;
         }
         else
         {
@@ -618,11 +642,12 @@
         # When selecting alternatives we have to consider defaults, for example:
         # lib l : l.cpp : <variant>debug ;
         # lib l : l_opt.cpp : <variant>release ;
- # won't work unless we add default value <variant>debug.
+ # will not work unless we add default value <variant>debug.
         property-set = [ $(p).add-defaults ] ;
 
- # The algorithm: we keep the current best viable alternative. When we've
- # got a new best viable alternative, we compare it with the current one.
+ # The algorithm: we keep the current best viable alternative. When we
+ # encounter a new best viable alternative, we compare it with the
+ # current one.
 
         local best ;
         local best-properties ;
@@ -679,12 +704,12 @@
 
     rule apply-default-build ( property-set )
     {
- return [ targets.apply-default-build $(property-set)
- : $(self.default-build) ] ;
+ return [ targets.apply-default-build $(property-set) :
+ $(self.default-build) ] ;
     }
 
     # Select an alternative for this main target, by finding all alternatives
- # which requirements are satisfied by 'properties' and picking the one with
+ # whose requirements are satisfied by 'properties' and picking the one with
     # the longest requirements set. Returns the result of calling 'generate' on
     # that alternative.
     #
@@ -692,8 +717,8 @@
     {
         start-building $(__name__) ;
 
- # We want composite properties in build request act as if all the
- # properties it expands too are explicitly specified.
+ # We want composite properties in the build request to act as if all the
+ # properties they expand to have been explicitly specified.
         property-set = [ $(property-set).expand ] ;
 
         local all-property-sets = [ apply-default-build $(property-set) ] ;
@@ -744,7 +769,7 @@
 }
 
 
-# Abstract target refering to a source file. This is an artificial entity
+# Abstract target referring to a source file. This is an artificial entity
 # allowing sources to a target to be represented using a list of abstract target
 # instances.
 #
@@ -840,6 +865,7 @@
     local rproperties = [ $(propagated).refine $(sproperties) ] ;
     if $(rproperties[1]) = "@error"
     {
+ import errors ;
         errors.error
             "When building" [ full-name ] " with properties " $(properties) :
             "Invalid properties specified for " $(source) ":"
@@ -848,10 +874,11 @@
     return [ $(target).generate $(rproperties) ] ;
 }
 
+
 rule apply-default-build ( property-set : default-build )
 {
- # 1. First, see what properties from default-build are already present
- # in property-set.
+ # 1. First, see what properties from default-build are already present in
+ # property-set.
 
     local raw = [ $(property-set).raw ] ;
     local specified-features = $(raw:G) ;
@@ -865,31 +892,23 @@
         }
     }
 
- # 2. If there are any defaults to be applied, form a new build request.
- # Pass it through to 'expand-no-defaults' since default-build might
- # contain "release debug" resulting in two property-sets.
+ # 2. If there are any defaults to be applied, form a new build request. Pass
+ # it through to 'expand-no-defaults' since default-build might contain
+ # "release debug" resulting in two property-sets.
     local result ;
     if $(defaults-to-apply)
     {
- properties = [
- build-request.expand-no-defaults
-
- # We have to compress subproperties here to prevent property
- # lists like:
- #
- # <toolset>msvc <toolset-msvc:version>7.1 <threading>multi
- #
- # from being expanded into:
- #
- # <toolset-msvc:version>7.1/<threading>multi
- # <toolset>msvc/<toolset-msvc:version>7.1/<threading>multi
- #
- # due to a cross-product property combination. That may be an
- # indication that build-request.expand-no-defaults is the wrong
- # rule to use here.
- [ feature.compress-subproperties $(raw) ]
- $(defaults-to-apply)
- ] ;
+ # We have to compress subproperties here to prevent property lists like:
+ # <toolset>msvc <toolset-msvc:version>7.1 <threading>multi
+ #
+ # from being expanded into:
+ # <toolset-msvc:version>7.1/<threading>multi
+ # <toolset>msvc/<toolset-msvc:version>7.1/<threading>multi
+ #
+ # due to a cross-product property combination. That may be an indication
+ # that build-request.expand-no-defaults is the wrong rule to use here.
+ properties = [ build-request.expand-no-defaults
+ [ feature.compress-subproperties $(raw) ] $(defaults-to-apply) ] ;
 
         if $(properties)
         {
@@ -967,8 +986,9 @@
     #
     # might come from project's requirements.
 
- local unconditional = [ feature.expand [ $(requirements).non-conditional ] ] ;
-
+ local unconditional = [ feature.expand [ $(requirements).non-conditional ] ]
+ ;
+
     local raw = [ $(context).raw ] ;
     raw = [ property.refine $(raw) : $(unconditional) ] ;
 
@@ -983,9 +1003,8 @@
     # the property set should stabilize before we are done. It is assumed that
     # #conditionals iterations should be enough for properties to propagate
     # along conditions in any direction.
- local count = $(conditionals)
- [ $(requirements).get <conditional> ]
- and-once-more ;
+ local count = $(conditionals) [ $(requirements).get <conditional> ]
+ and-once-more ;
 
     local added-requirements ;
 
@@ -1003,13 +1022,16 @@
     while $(count)
     {
         # Evaluate conditionals in context of current properties.
- local e = [ property.evaluate-conditionals-in-context $(conditionals)
- : $(current) ] ;
+ local e = [ property.evaluate-conditionals-in-context $(conditionals) :
+ $(current) ] ;
 
         # Evaluate indirect conditionals.
         for local i in $(indirect)
         {
- e += [ indirect.call $(i) $(current) ] ;
+ local t = [ current ] ;
+ local p = [ $(t).project ] ;
+ local new = [ indirect.call $(i) $(current) ] ;
+ e += [ property.translate-paths $(new) : [ $(p).location ] ] ;
         }
 
         if $(e) = $(added-requirements)
@@ -1030,7 +1052,8 @@
     }
     if ! $(ok)
     {
- errors.error "Can not evaluate conditional properties " $(conditionals) ;
+ import errors ;
+ errors.error Can not evaluate conditional properties $(conditionals) ;
     }
 
     if $(what) = added
@@ -1043,6 +1066,7 @@
     }
     else
     {
+ import errors ;
         errors.error "Invalid value of the 'what' parameter." ;
     }
 }
@@ -1051,21 +1075,23 @@
 rule common-properties2 ( build-request requirements )
 {
     # This guarantees that default properties are present in the result, unless
- # they are overriden by some requirement. FIXME: There is possibility that
+ # they are overriden by some requirement. FIXME: There is a possibility that
     # we have added <foo>bar, which is composite and expands to <foo2>bar2, but
     # default value of <foo2> is not bar2, in which case it is not clear what to
     # do.
     #
     build-request = [ $(build-request).add-defaults ] ;
- # Features added by 'add-default' can be composite and expand to features
- # without default values -- so they are not added yet. It could be clearer/
- # /faster to expand only newly added properties but that is not critical.
+ # Features added by 'add-defaults' can be composite and expand to features
+ # without default values -- which therefore have not been added yet. It
+ # could be clearer/faster to expand only newly added properties but that is
+ # not critical.
     build-request = [ $(build-request).expand ] ;
 
     return [ evaluate-requirements $(requirements) : $(build-request) :
         refined ] ;
 }
 
+
 rule push-target ( target )
 {
     .targets = $(target) $(.targets) ;
@@ -1092,7 +1118,6 @@
     import build-request ;
     import build-system ;
     import "class" : new ;
- import errors ;
     import feature ;
     import property ;
     import property-set ;
@@ -1101,13 +1126,14 @@
     import targets ;
     import virtual-target ;
 
- rule __init__ ( name : project : sources * : requirements *
- : default-build * : usage-requirements * )
+ rule __init__ ( name : project : sources * : requirements * :
+ default-build * : usage-requirements * )
     {
         abstract-target.__init__ $(name) : $(project) ;
 
         self.sources = $(sources) ;
- if ! $(requirements) {
+ if ! $(requirements)
+ {
             requirements = [ property-set.empty ] ;
         }
         self.requirements = $(requirements) ;
@@ -1124,16 +1150,17 @@
 
         if $(sources:G)
         {
- errors.user-error properties found in the 'sources' parameter for
- [ full-name ] ;
+ import errors : user-error : errors.user-error ;
+ errors.user-error properties found "in" the 'sources' parameter
+ "for" [ full-name ] ;
         }
     }
-
+
     rule always ( )
     {
         self.always = 1 ;
     }
-
+
     # Returns the list of abstract-targets which are used as sources. The extra
     # properties specified for sources are not represented. The only user for
     # this rule at the moment is the "--dump-tests" feature of the test system.
@@ -1144,8 +1171,8 @@
         {
             for local s in $(self.sources)
             {
- self.source-targets +=
- [ targets.resolve-reference $(s) : $(self.project) ] ;
+ self.source-targets += [ targets.resolve-reference $(s) :
+ $(self.project) ] ;
             }
         }
         return $(self.source-targets) ;
@@ -1178,7 +1205,8 @@
         local condition = [ set.difference $(bcondition) : $(ccondition) ] ;
         if $(debug)
         {
- ECHO " next alternative: required properties:" $(condition:E=(empty)) ;
+ ECHO " next alternative: required properties:"
+ $(condition:E=(empty)) ;
         }
 
         if $(condition) in [ $(property-set).raw ]
@@ -1200,19 +1228,19 @@
     }
 
     # Takes a target reference, which might be either target id or a dependency
- # property, and generates that target using 'property-set' as build request.
+ # property, and generates that target using 'property-set' as a build
+ # request.
     #
     # The results are added to the variable called 'result-var'. Usage
     # requirements are added to the variable called 'usage-requirements-var'.
     #
- rule generate-dependencies ( dependencies * : property-set
- : result-var usage-requirements-var )
+ rule generate-dependencies ( dependencies * : property-set : result-var
+ usage-requirements-var )
     {
         for local dependency in $(dependencies)
         {
             local grist = $(dependency:G) ;
             local id = $(dependency:G=) ;
-
             local result = [ targets.generate-from-reference $(id) :
                 $(self.project) : $(property-set) ] ;
 
@@ -1232,27 +1260,32 @@
             local fn = [ full-name ] ;
             ECHO [ targets.indent ] "Building target '$(fn)'" ;
             targets.increase-indent ;
- ECHO [ targets.indent ] "Build request: " $(property-set) [ $(property-set).raw ] ;
+ ECHO [ targets.indent ] Build request: $(property-set)
+ [ $(property-set).raw ] ;
             local cf = [ build-system.command-line-free-features ] ;
- ECHO [ targets.indent ] "Command line free features: " [ $(cf).raw ] ;
- ECHO [ targets.indent ] "Target requirements: " [ $(self.requirements).raw ] ;
+ ECHO [ targets.indent ] Command line free features: [ $(cf).raw ] ;
+ ECHO [ targets.indent ] Target requirements:
+ [ $(self.requirements).raw ] ;
         }
         targets.push-target $(__name__) ;
 
+ # Apply free features from the command line. If user said
+ # define=FOO
+ # he most likely wants this define to be set for all compiles.
+ # Make it before check for already built.
+ property-set = [ $(property-set).refine
+ [ build-system.command-line-free-features ] ] ;
+
         if ! $(self.generated.$(property-set))
         {
- # Apply free features from the command line. If user said
- # define=FOO
- # he most likely wants this define to be set for all compiles.
- property-set = [ $(property-set).refine
- [ build-system.command-line-free-features ] ] ;
             local rproperties = [ targets.common-properties $(property-set)
                 $(self.requirements) ] ;
 
             if [ modules.peek : .debug-building ]
             {
                 ECHO ;
- ECHO [ targets.indent ] "Common properties: " [ $(rproperties).raw ] ;
+ ECHO [ targets.indent ] "Common properties: "
+ [ $(rproperties).raw ] ;
             }
 
             if ( $(rproperties[1]) != "@error" ) && ( [ $(rproperties).get
@@ -1277,7 +1310,8 @@
 
                 rproperties = [ property-set.create $(properties)
                     $(usage-requirements) ] ;
- usage-requirements = [ property-set.create $(usage-requirements) ] ;
+ usage-requirements = [ property-set.create $(usage-requirements)
+ ] ;
 
                 if [ modules.peek : .debug-building ]
                 {
@@ -1288,11 +1322,11 @@
                 local extra = [ $(rproperties).get <source> ] ;
                 source-targets += $(extra:G=) ;
                 # We might get duplicate sources, for example if we link to two
- # libraries having the same <library> usage requirement.
- # Use stable sort, since for some targets the order is
- # important. E.g. RUN_PY target need python source to come
- # first.
- source-targets = [ sequence.unique $(source-targets) : stable ] ;
+ # libraries having the same <library> usage requirement. Use
+ # stable sort, since for some targets the order is important,
+ # e.g. RUN_PY targets need a python source to come first.
+ source-targets = [ sequence.unique $(source-targets) : stable ]
+ ;
 
                 local result = [ construct $(self.name) : $(source-targets) :
                     $(rproperties) ] ;
@@ -1301,15 +1335,15 @@
                 {
                     local gur = $(result[1]) ;
                     result = $(result[2-]) ;
-
+
                     if $(self.always)
                     {
                         for local t in $(result)
                         {
                             $(t).always ;
- }
+ }
                     }
-
+
                     local s = [ create-subvariant $(result)
                         : [ virtual-target.recent-targets ]
                         : $(property-set) : $(source-targets)
@@ -1361,7 +1395,8 @@
                 # - it is not clear if that is a good idea anyway. The alias
                 # target, for example, should not fail to build if a
                 # dependency fails.
- self.generated.$(property-set) = [ property-set.create <build>no ] ;
+ self.generated.$(property-set) = [ property-set.create <build>no
+ ] ;
             }
         }
         else
@@ -1464,6 +1499,7 @@
     #
     rule construct ( name : source-targets * : properties * )
     {
+ import errors : error : errors.error ;
         errors.error "method should be defined in derived classes" ;
     }
 }
@@ -1489,7 +1525,8 @@
 
     rule construct ( name : source-targets * : property-set )
     {
- local r = [ generators.construct $(self.project) $(name:S=) : $(self.type)
+ local r = [ generators.construct $(self.project) $(name:S=)
+ : $(self.type)
             : [ property-set.create [ $(property-set).raw ]
                 <main-target-type>$(self.type) ]
             : $(source-targets) : true ] ;
@@ -1498,15 +1535,15 @@
             ECHO "warn: Unable to construct" [ full-name ] ;
 
             # Are there any top-level generators for this type/property set.
- if ! [ generators.find-viable-generators $(self.type)
- : $(property-set) ]
+ if ! [ generators.find-viable-generators $(self.type) :
+ $(property-set) ]
             {
                 ECHO "error: no generators were found for type '$(self.type)'" ;
                 ECHO "error: and the requested properties" ;
                 ECHO "error: make sure you've configured the needed tools" ;
                 ECHO "See http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" ;
- ECHO "To debug this problem, try the --debug-generators option." ;
- EXIT ;
+ EXIT "To debug this problem, try the --debug-generators option."
+ ;
             }
         }
         return $(r) ;
@@ -1556,16 +1593,15 @@
     : project # Project where the main target is to be declared.
 )
 {
- specification += [ toolset.requirements ] ;
-
     local requirements = [ property-set.refine-from-user-input
         [ $(project).get requirements ] : $(specification) :
         [ $(project).project-module ] : [ $(project).get location ] ] ;
     if $(requirements[1]) = "@error"
     {
+ import errors ;
         errors.error "Conflicting requirements for target:" $(requirements) ;
     }
- return $(requirements) ;
+ return [ $(requirements).add [ toolset.requirements ] ] ;
 }
 
 
@@ -1623,37 +1659,36 @@
     return $(target) ;
 }
 
-# Creates a new metargets with the specified properties, using 'klass' as
-# the class. The 'name', 'sources',
-# 'requirements', 'default-build' and 'usage-requirements' are assumed to be in
-# the form specified by the user in Jamfile corresponding to 'project'.
+
+# Creates a metatarget with the specified properties, using 'klass' as the
+# class. The 'name', 'sources', 'requirements', 'default-build' and
+# 'usage-requirements' are assumed to be in the form specified by the user in
+# the Jamfile corresponding to 'project'.
 #
 rule create-metatarget ( klass : project : name : sources * : requirements * :
     default-build * : usage-requirements * )
 {
- return [
- targets.main-target-alternative
- [ new $(klass) $(name) : $(project)
- : [ targets.main-target-sources $(sources) : $(name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ]
- ] ] ;
+ return [ targets.main-target-alternative [ new $(klass) $(name) : $(project)
+ : [ targets.main-target-sources $(sources) : $(name) ]
+ : [ targets.main-target-requirements $(requirements) : $(project) ]
+ : [ targets.main-target-default-build $(default-build) : $(project) ]
+ : [ targets.main-target-usage-requirements $(usage-requirements) :
+ $(project) ] ] ] ;
 }
 
+
 # Creates a typed-target with the specified properties. The 'name', 'sources',
 # 'requirements', 'default-build' and 'usage-requirements' are assumed to be in
-# the form specified by the user in Jamfile corresponding to 'project'.
+# the form specified by the user in the Jamfile corresponding to 'project'.
 #
 rule create-typed-target ( type : project : name : sources * : requirements * :
     default-build * : usage-requirements * )
 {
- return [
- targets.main-target-alternative
- [ new typed-target $(name) : $(project) : $(type)
- : [ targets.main-target-sources $(sources) : $(name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ]
- ] ] ;
+ return [ targets.main-target-alternative [ new typed-target $(name) :
+ $(project) : $(type)
+ : [ targets.main-target-sources $(sources) : $(name) ]
+ : [ targets.main-target-requirements $(requirements) : $(project) ]
+ : [ targets.main-target-default-build $(default-build) : $(project) ]
+ : [ targets.main-target-usage-requirements $(usage-requirements) :
+ $(project) ] ] ] ;
 }

Modified: branches/release/tools/build/v2/build/toolset.jam
==============================================================================
--- branches/release/tools/build/v2/build/toolset.jam (original)
+++ branches/release/tools/build/v2/build/toolset.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 # Copyright 2005 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Support for toolset definition.
 
@@ -36,7 +37,8 @@
 rule using ( toolset-module : * )
 {
     import $(toolset-module) ;
- $(toolset-module).init $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ $(toolset-module).init $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9)
+ ;
 }
 
 
@@ -378,7 +380,8 @@
 
 rule filter-property-set ( rule-or-module : property-set )
 {
- if ! $(.filtered.property-set.$(rule-or-module).$(property-set))
+ local key = .filtered.property-set.$(rule-or-module).$(property-set) ;
+ if ! $($(key))
     {
         local relevant = [ relevant-features $(rule-or-module) ] ;
         local result ;
@@ -389,16 +392,16 @@
                 result += $(p) ;
             }
         }
- .filtered.property-set.$(rule-or-module).$(property-set) = [ property-set.create $(result) ] ;
+ $(key) = [ property-set.create $(result) ] ;
     }
- return $(.filtered.property-set.$(rule-or-module).$(property-set)) ;
+ return $($(key)) ;
 }
 
 rule set-target-variables ( rule-or-module targets + : property-set )
 {
     property-set = [ filter-property-set $(rule-or-module) : $(property-set) ] ;
- local key = $(rule-or-module).$(property-set) ;
- local settings = $(.stv.$(key)) ;
+ local key = .stv.$(rule-or-module).$(property-set) ;
+ local settings = $($(key)) ;
     if ! $(settings)
     {
         settings = [ set-target-variables-aux $(rule-or-module) :
@@ -408,7 +411,7 @@
         {
             settings = none ;
         }
- .stv.$(key) = $(settings) ;
+ $(key) = $(settings) ;
     }
 
     if $(settings) != none
@@ -497,8 +500,8 @@
         local rule-or-module = $(.rule-or-module.$(f)) ;
         if ( [ set.difference
             $(.$(rule-or-module).condition.$(f)) :
- $(prohibited-properties) ]
- || ! $(.$(rule-or-module).condition.$(f))
+ $(prohibited-properties) ]
+ || ! $(.$(rule-or-module).condition.$(f))
         ) && ( ! $(.$(rule-or-module).variable.$(f)) in $(prohibited-vars) )
         {
             local rule_ = [ MATCH "[^.]*\.(.*)" : $(rule-or-module) ] ;
@@ -536,6 +539,7 @@
     IMPORT $(toolset) : $(rules) : : $(toolset).$(rules) ;
 }
 
+.requirements = [ property-set.empty ] ;
 
 # Return the list of global 'toolset requirements'. Those requirements will be
 # automatically added to the requirements of any main target.
@@ -555,7 +559,10 @@
 {
     if ! $(.ignore-requirements)
     {
- .requirements += $(requirements) ;
+ requirements = [ property.translate-indirect $(specification) : [ CALLER_MODULE ] ] ;
+ requirements = [ property.expand-subfeatures-in-conditions $(requirements) ] ;
+ requirements = [ property.make $(requirements) ] ;
+ .requirements = [ $(.requirements).add-raw $(requirements) ] ;
     }
 }
 

Modified: branches/release/tools/build/v2/build/type.jam
==============================================================================
--- branches/release/tools/build/v2/build/type.jam (original)
+++ branches/release/tools/build/v2/build/type.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,13 +7,12 @@
 # typed targets.
 
 import "class" : new ;
-import errors ;
 import feature ;
 import generators : * ;
+import os ;
 import project ;
 import property ;
 import scanner ;
-import os ;
 
 # The following import would create a circular dependency:
 # project -> project-root -> builtin -> type -> targets -> project
@@ -39,20 +38,30 @@
     # decomposed.
     switch $(type)
     {
- case *-* : errors.error "type name \"$(type)\" contains a hyphen" ;
+ case *-* :
+ import errors ;
+ errors.error "type name \"$(type)\" contains a hyphen" ;
     }
 
     if $(type) in $(.types)
     {
+ import errors ;
         errors.error "Type $(type) is already registered." ;
     }
- else
+
     {
         .types += $(type) ;
         .base.$(type) = $(base-type) ;
         .derived.$(base-type) += $(type) ;
+ .bases.$(type) = $(type) $(.bases.$(base-type)) ;
 
- if $(suffixes)-is-not-empty
+ # Store suffixes for generated targets.
+ .suffixes.$(type) = [ new property-map ] ;
+
+ # Store prefixes for generated targets (e.g. "lib" for library).
+ .prefixes.$(type) = [ new property-map ] ;
+
+ if $(suffixes)-is-defined
         {
             # Specify mapping from suffixes to type.
             register-suffixes $(suffixes) : $(type) ;
@@ -119,6 +128,7 @@
         }
         else if $(.type.$(s)) != $(type)
         {
+ import errors ;
             errors.error Attempting to specify multiple types for suffix
                 \"$(s)\" : "Old type $(.type.$(s)), New type $(type)" ;
         }
@@ -143,6 +153,7 @@
 {
     if ! [ registered $(type) ]
     {
+ import errors ;
         errors.error "Unknown target type $(type)" ;
     }
 }
@@ -182,13 +193,7 @@
 #
 rule all-bases ( type )
 {
- local result = $(type) ;
- while $(type)
- {
- type = [ base $(type) ] ;
- result += $(type) ;
- }
- return $(result) ;
+ return $(.bases.$(type)) ;
 }
 
 
@@ -211,7 +216,7 @@
 #
 rule is-derived ( type base )
 {
- if $(base) in [ all-bases $(type) ]
+ if $(base) in $(.bases.$(type))
     {
         return true ;
     }
@@ -229,11 +234,6 @@
 }
 
 
-# Store suffixes for generated targets.
-.suffixes = [ new property-map ] ;
-
-# Store prefixes for generated targets (e.g. "lib" for library).
-.prefixes = [ new property-map ] ;
 
 
 # Sets a file suffix to be used when generating a target of 'type' with the
@@ -305,15 +305,13 @@
 
 local rule set-generated-target-ps ( ps : type : properties * : psval )
 {
- properties = <target-type>$(type) $(properties) ;
- $(.$(ps)es).insert $(properties) : $(psval) ;
+ $(.$(ps)es.$(type)).insert $(properties) : $(psval) ;
 }
 
 
 local rule change-generated-target-ps ( ps : type : properties * : psval )
 {
- properties = <target-type>$(type) $(properties) ;
- local prev = [ $(.$(ps)es).find-replace $(properties) : $(psval) ] ;
+ local prev = [ $(.$(ps)es.$(type)).find-replace $(properties) : $(psval) ] ;
     if ! $(prev)
     {
         set-generated-target-ps $(ps) : $(type) : $(properties) : $(psval) ;
@@ -326,17 +324,17 @@
 # 'ps' can be either "prefix" or "suffix". If no prefix/suffix is specified for
 # 'type', returns prefix/suffix for base type, if any.
 #
-local rule generated-target-ps-real ( ps : type : properties * )
+local rule generated-target-ps ( ps : type : property-set )
 {
     local result ;
     local found ;
     while $(type) && ! $(found)
     {
- result = [ $(.$(ps)es).find <target-type>$(type) $(properties) ] ;
+ result = [ $(.$(ps)es.$(type)).find $(property-set) ] ;
         # If the prefix/suffix is explicitly set to an empty string, we consider
         # prefix/suffix to be found. If we were not to compare with "", there
         # would be no way to specify an empty prefix/suffix.
- if $(result)-is-not-empty
+ if $(result)-is-defined
         {
             found = true ;
         }
@@ -350,28 +348,6 @@
 }
 
 
-local rule generated-target-ps ( ps : type : property-set )
-{
- local key = .$(ps).$(type).$(property-set) ;
- local v = $($(key)) ;
- if ! $(v)
- {
- v = [ generated-target-ps-real $(ps) : $(type) : [ $(property-set).raw ]
- ] ;
- if ! $(v)
- {
- v = none ;
- }
- $(key) = $(v) ;
- }
-
- if $(v) != none
- {
- return $(v) ;
- }
-}
-
-
 # Returns file type given its name. If there are several dots in filename, tries
 # each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and "so" will
 # be tried.
@@ -381,7 +357,7 @@
     if [ os.name ] in NT CYGWIN
     {
         filename = $(filename:L) ;
- }
+ }
     local type ;
     while ! $(type) && $(filename:S)
     {

Modified: branches/release/tools/build/v2/build/version.jam
==============================================================================
--- branches/release/tools/build/v2/build/version.jam (original)
+++ branches/release/tools/build/v2/build/version.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,19 +1,21 @@
 # Copyright 2002, 2003, 2004, 2006 Vladimir Prus
-# Copyright 2008 Jurko Gospodnetic
+# Copyright 2008, 2012 Jurko Gospodnetic
 # Distributed under the Boost Software License, Version 1.0.
 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
-import errors ;
 import numbers ;
 
-major = "2011" ;
-minor = "12" ;
+
+.major = "2011" ;
+.minor = "12" ;
+
 
 rule boost-build ( )
 {
- return "$(major).$(minor)-svn" ;
+ return "$(.major).$(.minor)-svn" ;
 }
 
+
 rule print ( )
 {
     if [ verify-engine-version ]
@@ -22,11 +24,12 @@
     }
 }
 
+
 rule verify-engine-version ( )
 {
     local v = [ modules.peek : JAM_VERSION ] ;
     
- if $(v[1]) != $(major) || $(v[2]) != $(minor)
+ if $(v[1]) != $(.major) || $(v[2]) != $(.minor)
     {
         local argv = [ modules.peek : ARGV ] ;
         local e = $(argv[1]) ;
@@ -44,7 +47,6 @@
 }
 
 
-
 # Utility rule for testing whether all elements in a sequence are equal to 0.
 #
 local rule is-all-zeroes ( sequence * )
@@ -105,14 +107,16 @@
     local version-tag = $(version:J=.) ;
     if ! $(version-tag)
     {
+ import errors ;
         errors.error Invalid version specifier: : $(version:E="(undefined)") ;
     }
 
- if ! $(.jam-version-check.$(version-tag))-is-not-empty
+ if ! $(.jam-version-check.$(version-tag))-is-defined
     {
         local jam-version = [ modules.peek : JAM_VERSION ] ;
         if ! $(jam-version)
         {
+ import errors ;
             errors.error "Unable to deduce Boost Jam version. Your Boost Jam"
                 "installation is most likely terribly outdated." ;
         }

Modified: branches/release/tools/build/v2/build/virtual-target.jam
==============================================================================
--- branches/release/tools/build/v2/build/virtual-target.jam (original)
+++ branches/release/tools/build/v2/build/virtual-target.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,22 +2,14 @@
 # Copyright 2005, 2006 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Implements virtual targets, which correspond to actual files created during a
 # build, but are not yet targets in Jam sense. They are needed, for example,
 # when searching for possible transformation sequences, when it is not yet known
 # whether a particular target should be created at all.
-
-import "class" : new ;
-import errors ;
-import path ;
-import sequence ;
-import set ;
-import type ;
-import utility ;
-
-
+#
 # +--------------------------+
 # | virtual-target |
 # +==========================+
@@ -65,6 +57,13 @@
 # The 'compile-action' and 'link-action' classes are not defined here but in
 # builtin.jam modules. They are shown in the diagram to give the big picture.
 
+import "class" : new ;
+import path ;
+import sequence ;
+import set ;
+import type ;
+import utility ;
+
 
 # Models a potential target. It can be converted into a Jam target and used in
 # building, if needed. However, it can be also dropped, which allows us to
@@ -113,12 +112,12 @@
     {
         return $(self.dependencies) ;
     }
-
+
     rule always ( )
     {
         .always = 1 ;
     }
-
+
     # Generates all the actual targets and sets up build actions for this
     # target.
     #
@@ -133,12 +132,12 @@
     rule actualize ( scanner ? )
     {
         local actual-name = [ actualize-no-scanner ] ;
-
+
         if $(.always)
         {
             ALWAYS $(actual-name) ;
         }
-
+
         if ! $(scanner)
         {
             return $(actual-name) ;
@@ -146,19 +145,15 @@
         else
         {
             # Add the scanner instance to the grist for name.
- local g = [ sequence.join
- [ utility.ungrist $(actual-name:G) ] $(scanner) : - ] ;
+ local g = [ sequence.join [ utility.ungrist $(actual-name:G) ]
+ $(scanner) : - ] ;
             local name = $(actual-name:G=$(g)) ;
 
- if ! $(self.made.$(name))
+ if ! $(self.made.$(scanner))
             {
- self.made.$(name) = true ;
-
- DEPENDS $(name) : $(actual-name) ;
-
+ self.made.$(scanner) = true ;
                 actualize-location $(name) ;
-
- scanner.install $(scanner) : $(name) $(__name__) ;
+ scanner.install $(scanner) : $(name) ;
             }
             return $(name) ;
         }
@@ -171,6 +166,7 @@
     #
     rule actualize-action ( target )
     {
+ import errors : error : errors.error ;
         errors.error "method should be defined in derived classes" ;
     }
 
@@ -178,6 +174,7 @@
     #
     rule actualize-location ( target )
     {
+ import errors : error : errors.error ;
         errors.error "method should be defined in derived classes" ;
     }
 
@@ -186,6 +183,7 @@
     #
     rule path ( )
     {
+ import errors : error : errors.error ;
         errors.error "method should be defined in derived classes" ;
     }
 
@@ -194,6 +192,7 @@
     #
     rule actual-name ( )
     {
+ import errors : error : errors.error ;
         errors.error "method should be defined in derived classes" ;
     }
 
@@ -203,7 +202,8 @@
         # In fact, we just need to merge virtual-target with
         # abstract-file-target as the latter is the only class derived from the
         # former. But that has been left for later.
-
+
+ import errors : error : errors.error ;
         errors.error "method should be defined in derived classes" ;
     }
 }
@@ -289,8 +289,8 @@
 
     # Gets or sets the subvariant which created this target. Subvariant is set
     # when target is brought into existance and is never changed after that. In
- # particular, if a target is shared by a subvariant, only the first is
- # stored.
+ # particular, if a target is shared by multiple subvariants, only the first
+ # one is stored.
     #
     rule creating-subvariant ( s ? # If specified, specifies the value to set,
                                     # which should be a 'subvariant' class
@@ -433,13 +433,6 @@
             ps = [ property-set.empty ] ;
         }
 
- # We add ourselves to the properties so that any tag rule can get more
- # direct information about the target than just that available through
- # the properties. This is useful in implementing name changes based on
- # the sources of the target. For example to make unique names of object
- # files based on the source file. --grafik
- ps = [ property-set.create [ $(ps).raw ] <target>$(__name__) ] ;
-
         local tag = [ $(ps).get <tag> ] ;
 
         if $(tag)
@@ -449,8 +442,9 @@
             {
                 if $(tag[2])
                 {
- errors.error "<tag>@rulename is present but is not the only"
- "<tag> feature" ;
+ import errors : error : errors.error ;
+ errors.error <tag>@rulename is present but is not the only
+ <tag> feature. ;
                 }
 
                 self.name = [ indirect.call $(rule-name) $(specified-name)
@@ -458,8 +452,8 @@
             }
             else
             {
- errors.error
- "The value of the <tag> feature must be '@rule-name'" ;
+ import errors : error : errors.error ;
+ errors.error <tag> property value must be '@rule-name'. ;
             }
         }
 
@@ -476,9 +470,9 @@
         local name = [ actual-name ] ;
 
         # Do anything only on the first invocation.
- if ! $(self.made.$(name))
+ if ! $(self.made-no-scanner)
         {
- self.made.$(name) = true ;
+ self.made-no-scanner = true ;
 
             if $(self.action)
             {
@@ -550,7 +544,6 @@
 {
     import "class" : new ;
     import common ;
- import errors ;
 
     rule __init__ (
         name exact ?
@@ -574,7 +567,31 @@
 
     rule actualize-location ( target )
     {
- if $(self.action)
+ # Scanner targets are always bound to already existing files in already
+ # existing folder. They need to be marked as depending on their base
+ # target (i.e. the target being scanned) but, unlike regular
+ # dependencies set up by the DEPENDS rule, they must not depend on any
+ # targets already marked as included by the base target. Otherwise such
+ # an included file being newer than the file being scanned would cause
+ # the scanner target to be updated, further causing any target depending
+ # on that scanner target to be rebuilt. This is the exact relationship
+ # as set up by Boost Jam's SEARCH binding method (needed to support
+ # searching for generated targets) so we want to bind scanner targets
+ # using this method instead of explicitly specifying their location
+ # using LOCATE.
+ #
+ # FIXME: We recognize scanner targets by their given name being
+ # different from this target's actual name. This is a hack and should be
+ # cleaned up by reorganizing who knows about scanners in the
+ # virtual-target/abstract-file-target/file-target/notfile-target/
+ # searched-lib-target/... class hierarchy.
+ local is-scanner-target ;
+ if $(target) != [ actual-name ]
+ {
+ is-scanner-target = true ;
+ }
+
+ if $(self.action) && ! $(is-scanner-target)
         {
             # This is a derived file.
             local path = [ path ] ;
@@ -597,12 +614,12 @@
             # For a real file target, we create a fake target depending on the
             # real target. This allows us to run
             #
- # bjam hello.o
+ # b2 hello.o
             #
             # without trying to guess the name of the real target. Note that the
             # target has no directory name and uses a special <e> grist.
             #
- # First, that means that "bjam hello.o" will build all known hello.o
+ # First, that means that "b2 hello.o" will build all known hello.o
             # targets. Second, the <e> grist makes sure this target will not be
             # confused with other targets, for example, if we have subdir 'test'
             # with target 'test' in it that includes a 'test.o' file, then the
@@ -610,7 +627,7 @@
             # will be <ptest/bin/gcc/debug>test.o and the target we create below
             # will be <e>test.o
             DEPENDS $(target:G=e) : $(target) ;
- # Allow bjam <path-to-file>/<file> to work. This will not catch all
+ # Allow b2 <path-to-file>/<file> to work. This will not catch all
             # possible ways to refer to the path (relative/absolute, extra ".",
             # various "..", but should help in obvious cases.
             DEPENDS $(target:G=e:R=$(path)) : $(target) ;
@@ -681,13 +698,12 @@
 class action
 {
     import "class" ;
- import errors ;
- import type ;
- import toolset ;
- import property-set ;
     import indirect ;
     import path ;
+ import property-set ;
     import set : difference ;
+ import toolset ;
+ import type ;
 
     rule __init__ ( sources * : action-name + : property-set ? )
     {
@@ -702,6 +718,7 @@
 
         if ! [ class.is-instance $(property-set) ]
         {
+ import errors : error : errors.error ;
             errors.error "Property set instance required" ;
         }
 
@@ -760,22 +777,9 @@
 
             DEPENDS $(actual-targets) : $(self.actual-sources)
                 $(self.dependency-only-sources) ;
-
- # This works around a bug with -j and actions that
- # produce multiple target, where:
- # - dependency on the first output is found, and
- # the action is started
- # - dependency on the second output is found, and
- # bjam noticed that command is already running
- # - instead of waiting for the command, dependents
- # of the second targets are immediately updated.
- if $(actual-targets[2])
- {
- INCLUDES $(actual-targets) : $(actual-targets) ;
- }
-
- # Action name can include additional argument to rule, which should
- # not be passed to 'set-target-variables'
+
+ # Action name can include additional rule arguments, which should
+ # not be passed to 'set-target-variables'.
             toolset.set-target-variables
                 [ indirect.get-rule $(self.action-name[1]) ] $(actual-targets)
                 : $(properties) ;
@@ -831,15 +835,15 @@
         self.actual-sources +=
             [ actualize-source-type $(sources) : $(property-set) ] ;
 
- # This is used to help bjam find dependencies in generated headers and
+ # This is used to help b2 find dependencies in generated headers and
         # other main targets, e.g. in:
         #
         # make a.h : ....... ;
         # exe hello : hello.cpp : <implicit-dependency>a.h ;
         #
- # For bjam to find the dependency the generated target must be
+ # For b2 to find the dependency the generated target must be
         # actualized (i.e. have its Jam target constructed). In the above case,
- # if we are building just hello ("bjam hello"), 'a.h' will not be
+ # if we are building just hello ("b2 hello"), 'a.h' will not be
         # actualized unless we do it here.
         local implicit = [ $(self.properties).get <implicit-dependency> ] ;
         for local i in $(implicit)
@@ -955,8 +959,8 @@
 #
 rule register ( target )
 {
- local signature = [ sequence.join
- [ $(target).path ] [ $(target).name ] : - ] ;
+ local signature = [ sequence.join [ $(target).path ] [ $(target).name ] : -
+ ] ;
 
     local result ;
     for local t in $(.cache.$(signature))
@@ -970,22 +974,19 @@
             {
                 result = $(t) ;
             }
- else
- {
- if $(a1) && $(a2) &&
- ( [ $(a1).action-name ] = [ $(a2).action-name ] ) &&
- ( [ $(a1).sources ] = [ $(a2).sources ] )
+ else if $(a1) && $(a2) &&
+ ( [ $(a1).action-name ] = [ $(a2).action-name ] ) &&
+ ( [ $(a1).sources ] = [ $(a2).sources ] )
+ {
+ local ps1 = [ $(a1).properties ] ;
+ local ps2 = [ $(a2).properties ] ;
+ local p1 = [ $(ps1).base ] [ $(ps1).free ] [ set.difference
+ [ $(ps1).dependency ] : [ $(ps1).incidental ] ] ;
+ local p2 = [ $(ps2).base ] [ $(ps2).free ] [ set.difference
+ [ $(ps2).dependency ] : [ $(ps2).incidental ] ] ;
+ if $(p1) = $(p2)
                 {
- local ps1 = [ $(a1).properties ] ;
- local ps2 = [ $(a2).properties ] ;
- local p1 = [ $(ps1).base ] [ $(ps1).free ] [ set.difference
- [ $(ps1).dependency ] : [ $(ps1).incidental ] ] ;
- local p2 = [ $(ps2).base ] [ $(ps2).free ] [ set.difference
- [ $(ps2).dependency ] : [ $(ps2).incidental ] ] ;
- if $(p1) = $(p2)
- {
- result = $(t) ;
- }
+ result = $(t) ;
                 }
             }
         }
@@ -1051,9 +1052,26 @@
     if $(.actual.$(actual-name))
     {
         local cs1 = [ $(.actual.$(actual-name)).creating-subvariant ] ;
+ local cmt1-name ;
+ if $(cs1)-is-defined
+ {
+ local cmt1 = [ $(cs1).main-target ] ;
+ cmt1-name = [ $(cmt1).full-name ] ;
+ }
         local cs2 = [ $(virtual-target).creating-subvariant ] ;
- local cmt1 = [ $(cs1).main-target ] ;
- local cmt2 = [ $(cs2).main-target ] ;
+ local cmt2-name ;
+ if $(cs2)-is-defined
+ {
+ local cmt2 = [ $(cs2).main-target ] ;
+ cmt2-name = [ $(cmt2).full-name ] ;
+ }
+ local extra-error-information ;
+ if ! $(cs1)-is-defined || ! $(cs2)-is-defined
+ {
+ extra-error-information = Encountered a virtual-target without a
+ creating subvariant. It could be the virtual target has not been
+ registered via the virtual-target.register rule. ;
+ }
 
         local action1 = [ $(.actual.$(actual-name)).action ] ;
         local action2 = [ $(virtual-target).action ] ;
@@ -1070,13 +1088,15 @@
             properties-added = [ set.difference $(p2) : $(p1) ] ;
             properties-added ?= "none" ;
         }
+ import errors : error : errors.error ;
         errors.error "Duplicate name of actual target:" $(actual-name)
             : "previous virtual target" [ $(.actual.$(actual-name)).str ]
- : "created from" [ $(cmt1).full-name ]
+ : "created from" $(cmt1-name)
             : "another virtual target" [ $(virtual-target).str ]
- : "created from" [ $(cmt2).full-name ]
+ : "created from" $(cmt2-name)
             : "added properties:" $(properties-added)
- : "removed properties:" $(properties-removed) ;
+ : "removed properties:" $(properties-removed)
+ : $(extra-error-information) ;
     }
     else
     {
@@ -1104,7 +1124,8 @@
         {
             if ! [ $(t).root ]
             {
- result += [ traverse $(t) : $(include-roots) : $(include-sources) ] ;
+ result += [ traverse $(t) : $(include-roots) :
+ $(include-sources) ] ;
             }
             else if $(include-roots)
             {
@@ -1125,7 +1146,8 @@
 # 'new-rule-name' and 'new-properties', if those are specified. Returns the
 # cloned action.
 #
-rule clone-action ( action : new-project : new-action-name ? : new-properties ? )
+rule clone-action ( action : new-project : new-action-name ? : new-properties ?
+ )
 {
     if ! $(new-action-name)
     {
@@ -1245,7 +1267,7 @@
             {
                 $(theset).add $(t) ;
                 r += [ $(t:G=).creating-subvariant ] ;
- }
+ }
         }
         r = [ sequence.unique $(r) ] ;
         for local s in $(r)
@@ -1259,7 +1281,7 @@
 
     # Returns the properties specifying implicit include paths to generated
     # headers. This traverses all targets in this subvariant and subvariants
- # referred by <implcit-dependecy> properties. For all targets of type
+ # referred by <implicit-dependecy> properties. For all targets of type
     # 'target-type' (or for all targets, if 'target-type' is not specified), the
     # result will contain <$(feature)>path-to-that-target.
     #

Modified: branches/release/tools/build/v2/build/virtual_target.py
==============================================================================
--- branches/release/tools/build/v2/build/virtual_target.py (original)
+++ branches/release/tools/build/v2/build/virtual_target.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,6 +1,6 @@
 # Status: ported.
 # Base revision: 64488.
-#
+#
 # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and
 # distribute this software is granted provided this copyright notice appears in
 # all copies. This software is provided "as is" without express or implied
@@ -13,7 +13,7 @@
 #
 #
 # +--------------------------+
-# | VirtualTarget |
+# | VirtualTarget |
 # +==========================+
 # | actualize |
 # +--------------------------+
@@ -85,7 +85,7 @@
 class VirtualTargetRegistry:
     def __init__ (self, manager):
         self.manager_ = manager
-
+
         # A cache for FileTargets
         self.files_ = {}
 
@@ -98,12 +98,12 @@
         self.actual_ = {}
 
         self.recent_targets_ = []
-
+
         # All targets ever registed
         self.all_targets_ = []
 
         self.next_id_ = 0
-
+
     def register (self, target):
         """ Registers a new virtual target. Checks if there's already registered target, with the same
             name, type, project and subvariant properties, and also with the same sources
@@ -137,7 +137,7 @@
                             b2.util.set.difference(ps2.dependency(), ps2.incidental())
                         if p1 == p2:
                             result = t
-
+
         if not result:
             self.cache_ [signature].append (target)
             result = target
@@ -145,7 +145,7 @@
         # TODO: Don't append if we found pre-existing target?
         self.recent_targets_.append(result)
         self.all_targets_.append(result)
-
+
         return result
 
     def from_file (self, file, file_location, project):
@@ -166,9 +166,9 @@
         file_type = b2.build.type.type (file)
 
         result = FileTarget (file, file_type, project,
- None, file_location)
+ None, file_location)
         self.files_ [path] = result
-
+
         return result
 
     def recent_targets(self):
@@ -196,11 +196,11 @@
             cs1 = self.actual_ [actual_name].creating_subvariant ()
             cs2 = virtual_target.creating_subvariant ()
             cmt1 = cs1.main_target ()
- cmt2 = cs2.main_target ()
-
+ cmt2 = cs2.main_target ()
+
             action1 = self.actual_ [actual_name].action ()
             action2 = virtual_target.action ()
-
+
             properties_added = []
             properties_removed = []
             if action1 and action2:
@@ -208,7 +208,7 @@
                 p1 = p1.raw ()
                 p2 = action2.properties ()
                 p2 = p2.raw ()
-
+
                 properties_removed = set.difference (p1, p2)
                 if not properties_removed: properties_removed = "none"
 
@@ -217,7 +217,7 @@
 
             # FIXME: Revive printing of real location.
             get_manager().errors()(
- "Duplicate name of actual target: '%s'\n"
+ "Duplicate name of actual target: '%s'\n"
                 "previous virtual target '%s'\n"
                 "created from '%s'\n"
                 "another virtual target '%s'\n"
@@ -226,13 +226,13 @@
                 "removed properties: '%s'\n"
                 % (actual_name,
                    self.actual_ [actual_name], "loc", #cmt1.location (),
- virtual_target,
+ virtual_target,
                    "loc", #cmt2.location (),
                    properties_added, properties_removed))
 
         else:
             self.actual_ [actual_name] = virtual_target
-
+
 
     def add_suffix (self, specified_name, file_type, prop_set):
         """ Appends the suffix appropriate to 'type/property_set' combination
@@ -245,7 +245,7 @@
 
         else:
             return specified_name
-
+
 class VirtualTarget:
     """ Potential target. It can be converted into jam target and used in
         building, if needed. However, it can be also dropped, which allows
@@ -258,7 +258,7 @@
         self.project_ = project
         self.dependencies_ = []
         self.always_ = False
-
+
         # Caches if dapendencies for scanners have already been set.
         self.made_ = {}
 
@@ -293,13 +293,13 @@
     def actualize (self, scanner = None):
         """ Generates all the actual targets and sets up build actions for
             this target.
-
+
             If 'scanner' is specified, creates an additional target
             with the same location as actual target, which will depend on the
             actual target and be associated with 'scanner'. That additional
             target is returned. See the docs (#dependency_scanning) for rationale.
             Target must correspond to a file if 'scanner' is specified.
-
+
             If scanner is not specified, then actual target is returned.
         """
         actual_name = self.actualize_no_scanner ()
@@ -339,13 +339,13 @@
         """ Sets up variables on 'target' which specify its location.
         """
         raise BaseException ("method should be defined in derived classes")
-
+
     def path (self):
         """ If the target is generated one, returns the path where it will be
             generated. Otherwise, returns empty list.
         """
         raise BaseException ("method should be defined in derived classes")
-
+
     def actual_name (self):
         """ Return that actual target name that should be used
             (for the case where no scanner is involved)
@@ -357,41 +357,41 @@
     """ Target which correspond to a file. The exact mapping for file
         is not yet specified in this class. (TODO: Actually, the class name
         could be better...)
-
+
         May be a source file (when no action is specified), or
         derived file (otherwise).
-
+
         The target's grist is concatenation of project's location,
         properties of action (for derived files), and, optionally,
         value identifying the main target.
-
+
         exact: If non-empty, the name is exactly the name
                 created file should have. Otherwise, the '__init__'
                 method will add suffix obtained from 'type' by
                 calling 'type.generated-target-suffix'.
-
+
         type: optional type of this target.
     """
     def __init__ (self, name, type, project, action = None, exact=False):
         VirtualTarget.__init__ (self, name, project)
-
+
         self.type_ = type
 
         self.action_ = action
         self.exact_ = exact
-
+
         if action:
             action.add_targets ([self])
-
+
             if self.type and not exact:
                 self.__adjust_name (name)
 
-
+
         self.actual_name_ = None
         self.path_ = None
         self.intermediate_ = False
         self.creating_subvariant_ = None
-
+
         # True if this is a root target.
         self.root_ = False
 
@@ -420,7 +420,7 @@
     def creating_subvariant (self, s = None):
         """ Gets or sets the subvariant which created this target. Subvariant
         is set when target is brought into existance, and is never changed
- after that. In particual, if target is shared by subvariant, only
+ after that. In particual, if target is shared by subvariant, only
         the first is stored.
         s: If specified, specified the value to set,
                 which should be instance of 'subvariant' class.
@@ -456,11 +456,11 @@
         if a:
             action_name = a.action_name()
             ss = [ s.str() for s in a.sources()]
-
+
             return "{ %s-%s %s}" % (action_name, name_dot_type, str(ss))
         else:
             return "{ " + name_dot_type + " }"
-
+
 # private:
 
     def actual_name (self):
@@ -475,10 +475,10 @@
             file.
         """
         # Depending on target, there may be different approaches to generating
- # unique prefixes. We'll generate prefixes in the form
+ # unique prefixes. We'll generate prefixes in the form
         # <one letter approach code> <the actual prefix>
         path = self.path ()
-
+
         if path:
             # The target will be generated to a known path. Just use the path
             # for identification, since path is as unique as it can get.
@@ -490,7 +490,7 @@
             project_location = self.project_.get ('location')
             path_components = b2.util.path.split(project_location)
             location_grist = '!'.join (path_components)
-
+
             if self.action_:
                 ps = self.action_.properties ()
                 property_grist = ps.as_path ()
@@ -498,20 +498,20 @@
                 # property set.
                 if property_grist:
                     location_grist = location_grist + '/' + property_grist
-
+
             return 'l' + location_grist
 
     def __adjust_name(self, specified_name):
         """Given the target name specified in constructor, returns the
         name which should be really used, by looking at the <tag> properties.
         The tag properties come in two flavour:
- - <tag>value,
+ - <tag>value,
           - <tag>@rule-name
         In the first case, value is just added to name
         In the second case, the specified rule is called with specified name,
         target type and properties and should return the new name.
         If not <tag> property is specified, or the rule specified by
- <tag> returns nothing, returns the result of calling
+ <tag> returns nothing, returns the result of calling
         virtual-target.add-suffix"""
 
         if self.action_:
@@ -529,9 +529,9 @@
         #~ --grafik
         #ps = property_set.create(ps.raw() + ["<target>%s" % "XXXX"])
         #ps = [ property-set.create [ $(ps).raw ] <target>$(__name__) ] ;
-
+
         tag = ps.get("<tag>")
-
+
         if tag:
 
             if len(tag) > 1:
@@ -550,7 +550,7 @@
                     tag[1:], specified_name, self.type_, exported_ps)
                 if self.name_:
                     self.name_ = self.name_[0]
-
+
         # If there's no tag or the tag rule returned nothing.
         if not tag or not self.name_:
             self.name_ = add_prefix_and_suffix(specified_name, self.type_, ps)
@@ -562,7 +562,7 @@
         if not self.made_:
             self.made_[name] = True
 
- if self.action_:
+ if self.action_:
                 # For non-derived target, we don't care if there
                 # are several virtual targets that refer to the same name.
                 # One case when this is unavoidable is when file name is
@@ -575,7 +575,7 @@
 
             self.actualize_location(name)
             self.actualize_action(name)
-
+
         return name
 
 @bjam_signature((["specified_name"], ["type"], ["property_set"]))
@@ -588,7 +588,7 @@
     suffix = ""
     if type:
         suffix = b2.build.type.generated_target_suffix(type, property_set)
-
+
     # Handle suffixes for which no leading dot is desired. Those are
     # specified by enclosing them in <...>. Needed by python so it
     # can create "_d.so" extensions, for example.
@@ -621,7 +621,7 @@
              are not equal to the project's reference properties
              an element with name of main target is added.
            - for source files, project's source dir
-
+
         The file suffix is
             - the value passed to the 'suffix' method, if any, or
             - the suffix which correspond to the target's type.
@@ -640,7 +640,7 @@
     def clone_with_different_type(self, new_type):
         return FileTarget(self.name_, new_type, self.project_,
                           self.action_, self.path_, exact=True)
-
+
     def actualize_location (self, target):
         engine = self.project_.manager_.engine ()
 
@@ -667,7 +667,7 @@
             #
             # bjam hello.o
             #
- # without trying to guess the name of the real target.
+ # without trying to guess the name of the real target.
             # Note the that target has no directory name, and a special
             # grist <e>.
             #
@@ -685,25 +685,25 @@
             # possible ways to refer to the path (relative/absolute, extra ".",
             # various "..", but should help in obvious cases.
             engine.add_dependency("<e>%s" % (os.path.join(path, get_value(target))), target)
-
+
         else:
             # This is a source file.
             engine.set_target_variable (target, 'SEARCH', self.project_.get ('source-location'))
-
+
 
     def path (self):
         """ Returns the directory for this target.
         """
         if not self.path_:
             if self.action_:
- p = self.action_.properties ()
+ p = self.action_.properties ()
                 (target_path, relative_to_build_dir) = p.target_path ()
-
+
                 if relative_to_build_dir:
                     # Indicates that the path is relative to
                     # build dir.
                     target_path = os.path.join (self.project_.build_dir (), target_path)
-
+
                 # Store the computed path, so that it's not recomputed
                 # any more
                 self.path_ = target_path
@@ -752,11 +752,11 @@
 
         # Indicates whether this has been actualized or not.
         self.actualized_ = False
-
+
         self.dependency_only_sources_ = []
         self.actual_sources_ = []
-
-
+
+
     def add_targets (self, targets):
         self.targets_ += targets
 
@@ -781,7 +781,7 @@
         """
         if self.actualized_:
             return
-
+
         self.actualized_ = True
 
         ps = self.properties ()
@@ -789,7 +789,7 @@
 
 
         actual_targets = []
-
+
         for i in self.targets ():
             actual_targets.append (i.actualize ())
 
@@ -797,34 +797,23 @@
 
         self.engine_.add_dependency (actual_targets, self.actual_sources_ + self.dependency_only_sources_)
 
- # This works around a bug with -j and actions that
- # produce multiple target, where:
- # - dependency on the first output is found, and
- # the action is started
- # - dependency on the second output is found, and
- # bjam noticed that command is already running
- # - instead of waiting for the command, dependents
- # of the second targets are immediately updated.
- if len(actual_targets) > 1:
- bjam.call("INCLUDES", actual_targets, actual_targets)
-
         # FIXME: check the comment below. Was self.action_name_ [1]
- # Action name can include additional argument to rule, which should not
- # be passed to 'set-target-variables'
+ # Action name can include additional rule arguments, which should not
+ # be passed to 'set-target-variables'.
         # FIXME: breaking circular dependency
         import toolset
         toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties)
-
+
         engine = self.manager_.engine ()
 
         # FIXME: this is supposed to help --out-xml option, but we don't
         # implement that now, and anyway, we should handle it in Python,
         # not but putting variables on bjam-level targets.
         bjam.call("set-target-variable", actual_targets, ".action", repr(self))
-
+
         self.manager_.engine ().set_update_action (self.action_name_, actual_targets, self.actual_sources_,
                                                    properties)
-
+
         # Since we set up creating action here, we also set up
         # action for cleaning up
         self.manager_.engine ().set_update_action ('common.Clean', 'clean-all',
@@ -844,27 +833,27 @@
 # FIXME: what's this?
 # if isinstance (i, str):
 # i = self.manager_.get_object (i)
-
+
             if i.type ():
                 scanner = b2.build.type.get_scanner (i.type (), prop_set)
 
             r = i.actualize (scanner)
             result.append (r)
-
+
         return result
-
+
     def actualize_sources (self, sources, prop_set):
         """ Creates actual jam targets for sources. Initializes two member
             variables:
             'self.actual_sources_' -- sources which are passed to updating action
             'self.dependency_only_sources_' -- sources which are made dependencies, but
             are not used otherwise.
-
+
             New values will be *appended* to the variables. They may be non-empty,
             if caller wants it.
         """
         dependencies = self.properties_.get ('<dependency>')
-
+
         self.dependency_only_sources_ += self.actualize_source_type (dependencies, prop_set)
         self.actual_sources_ += self.actualize_source_type (sources, prop_set)
 
@@ -896,12 +885,12 @@
 class NullAction (Action):
     """ Action class which does nothing --- it produces the targets with
         specific properties out of nowhere. It's needed to distinguish virtual
- targets with different properties that are known to exist, and have no
+ targets with different properties that are known to exist, and have no
         actions which create them.
     """
     def __init__ (self, manager, prop_set):
         Action.__init__ (self, manager, [], None, prop_set)
-
+
     def actualize (self):
         if not self.actualized_:
             self.actualized_ = True
@@ -932,10 +921,10 @@
         value of 'include_roots'. In either case, sources of root are not traversed.
     """
     result = []
-
+
     if target.action ():
         action = target.action ()
-
+
         # This includes 'target' as well
         result += action.targets ()
 
@@ -945,7 +934,7 @@
             # TODO: see comment in Manager.register_object ()
             #if not isinstance (t, VirtualTarget):
             # t = target.project_.manager_.get_object (t)
-
+
             if not t.root ():
                 result += traverse (t, include_roots, include_sources)
 
@@ -971,7 +960,7 @@
 
     cloned_action = action.__class__(action.manager_, action.sources(), new_action_name,
                                      new_properties)
-
+
     cloned_targets = []
     for target in action.targets():
 
@@ -991,9 +980,9 @@
     return cloned_action
 
 class Subvariant:
-
+
     def __init__ (self, main_target, prop_set, sources, build_properties, sources_usage_requirements, created_targets):
- """
+ """
         main_target: The instance of MainTarget class
         prop_set: Properties requested for this target
         sources:
@@ -1009,11 +998,11 @@
         self.created_targets_ = created_targets
 
         self.usage_requirements_ = None
-
+
         # Pre-compose the list of other dependency graphs, on which this one
         # depends
         deps = build_properties.get('<implicit-dependency>')
-
+
         self.other_dg_ = []
         for d in deps:
             self.other_dg_.append(d.creating_subvariant ())
@@ -1022,25 +1011,25 @@
 
         self.implicit_includes_cache_ = {}
         self.target_directories_ = None
-
+
     def main_target (self):
         return self.main_target_
-
+
     def created_targets (self):
         return self.created_targets_
-
+
     def requested_properties (self):
         return self.properties_
-
+
     def build_properties (self):
         return self.build_properties_
-
+
     def sources_usage_requirements (self):
         return self.sources_usage_requirements_
-
+
     def set_usage_requirements (self, usage_requirements):
         self.usage_requirements_ = usage_requirements
-
+
     def usage_requirements (self):
         return self.usage_requirements_
 
@@ -1053,7 +1042,7 @@
         # Find directly referenced targets.
         deps = self.build_properties().dependency()
         all_targets = self.sources_ + deps
-
+
         # Find other subvariants.
         r = []
         for e in all_targets:
@@ -1063,7 +1052,7 @@
                     t = e.value()
                 else:
                     t = e
-
+
                 # FIXME: how can this be?
                 cs = t.creating_subvariant()
                 if cs:
@@ -1088,7 +1077,7 @@
         else:
             key = feature + "-" + target_type
 
-
+
         result = self.implicit_includes_cache_.get(key)
         if not result:
             target_paths = self.all_target_directories(target_type)

Modified: branches/release/tools/build/v2/build_system.py
==============================================================================
--- branches/release/tools/build/v2/build_system.py (original)
+++ branches/release/tools/build/v2/build_system.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,12 +2,12 @@
 # and some FIXME.
 # Base revision: 64351
 
-# Copyright 2003, 2005 Dave Abrahams
-# Copyright 2006 Rene Rivera
-# Copyright 2003, 2004, 2005, 2006, 2007 Vladimir Prus
-# 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)
-
+# Copyright 2003, 2005 Dave Abrahams
+# Copyright 2006 Rene Rivera
+# Copyright 2003, 2004, 2005, 2006, 2007 Vladimir Prus
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 
 from b2.build.engine import Engine
@@ -49,16 +49,6 @@
 # locating and loading Boost Build configuration files.
 debug_config = False
 
-# Legacy option doing too many things, some of which are not even documented.
-# Should be phased out.
-# * Disables loading site and user configuration files.
-# * Disables auto-configuration for toolsets specified explicitly on the
-# command-line.
-# * Causes --toolset command-line options to be ignored.
-# * Prevents the default toolset from being used even if no toolset has been
-# configured at all.
-legacy_ignore_config = False
-
 # The cleaning is tricky. Say, if user says 'bjam --clean foo' where 'foo' is a
 # directory, then we want to clean targets which are in 'foo' as well as those
 # in any children Jamfiles under foo but not in any unrelated Jamfiles. To
@@ -104,7 +94,7 @@
     default_toolset = toolset
     default_toolset_version = version
 
-
+
 pre_build_hook = []
 
 def add_pre_build_hook(callable):
@@ -198,7 +188,7 @@
 
     if where:
         where = os.path.realpath(where)
-
+
         if debug_config:
             print "notice: Loading '%s' configuration file '%s' from '%s'." \
                   % (module_name, filename, where)
@@ -210,7 +200,7 @@
         attributes = get_manager().projects().attributes(module_name) ;
         attributes.set('source-location', os.path.dirname(where), True)
         get_manager().projects().load_standalone(module_name, where)
-
+
     else:
         msg = "Configuration file '%s' not found in '%s'." % (filename, path)
         if must_find:
@@ -225,17 +215,16 @@
 #
 # -- test-config --
 # Loaded only if specified on the command-line using the --test-config
-# command-line parameter. It is ok for this file not to exist even if specified.
-# If this configuration file is loaded, regular site and user configuration
-# files will not be. If a relative path is specified, file is searched for in
-# the current folder.
+# command-line parameter. It is ok for this file not to exist even if
+# specified. If this configuration file is loaded, regular site and user
+# configuration files will not be. If a relative path is specified, file is
+# searched for in the current folder.
 #
 # -- site-config --
 # Always named site-config.jam. Will only be found if located on the system
-# root path (Windows), /etc (non-Windows), user's home folder or the Boost Build
-# path, in that order. Not loaded in case the test-config configuration file is
-# loaded or either the --ignore-site-config or the --ignore-config command-line
-# option is specified.
+# root path (Windows), /etc (non-Windows), user's home folder or the Boost
+# Build path, in that order. Not loaded in case the test-config configuration
+# file is loaded or the --ignore-site-config command-line option is specified.
 #
 # -- user-config --
 # Named user-config.jam by default or may be named explicitly using the
@@ -243,23 +232,18 @@
 # variable. If named explicitly the file is looked for from the current working
 # directory and if the default one is used then it is searched for in the
 # user's home directory and the Boost Build path, in that order. Not loaded in
-# case either the test-config configuration file is loaded, --ignore-config
-# command-line option is specified or an empty file name is explicitly
-# specified. If the file name has been given explicitly then the file must
-# exist.
+# case either the test-config configuration file is loaded or an empty file
+# name is explicitly specified. If the file name has been given explicitly then
+# the file must exist.
 #
 # Test configurations have been added primarily for use by Boost Build's
 # internal unit testing system but may be used freely in other places as well.
 #
 def load_configuration_files():
-
+
     # Flag indicating that site configuration should not be loaded.
     ignore_site_config = "--ignore-site-config" in sys.argv
 
- if legacy_ignore_config and debug_config:
- print "notice: Regular site and user configuration files will be ignored"
- print "notice: due to the --ignore-config command-line option."
-
     initialize_config_module("test-config")
     test_config = None
     for a in sys.argv:
@@ -271,7 +255,7 @@
     if test_config:
         where = load_config("test-config", os.path.basename(test_config), [os.path.dirname(test_config)])
         if where:
- if debug_config and not legacy_ignore_config:
+ if debug_config:
                 print "notice: Regular site and user configuration files will"
                 print "notice: be ignored due to the test configuration being loaded."
 
@@ -280,16 +264,16 @@
     if os.name in ["nt"]:
         site_path = [os.getenv("SystemRoot")] + user_path
 
- if ignore_site_config and not legacy_ignore_config:
+ if debug_config and not test_config and ignore_site_config:
         print "notice: Site configuration files will be ignored due to the"
         print "notice: --ignore-site-config command-line option."
 
     initialize_config_module("site-config")
- if not test_config and not ignore_site_config and not legacy_ignore_config:
+ if not test_config and not ignore_site_config:
         load_config('site-config', 'site-config.jam', site_path)
 
     initialize_config_module('user-config')
- if not test_config and not legacy_ignore_config:
+ if not test_config:
 
         # Here, user_config has value of None if nothing is explicitly
         # specified, and value of '' if user explicitly does not want
@@ -303,12 +287,12 @@
 
         if user_config is None:
             user_config = os.getenv("BOOST_BUILD_USER_CONFIG")
-
+
         # Special handling for the case when the OS does not strip the quotes
         # around the file name, as is the case when using Cygwin bash.
         user_config = b2.util.unquote(user_config)
         explicitly_requested = user_config
-
+
         if user_config is None:
             user_config = "user-config.jam"
 
@@ -316,25 +300,24 @@
             if explicitly_requested:
 
                 user_config = os.path.abspath(user_config)
-
+
                 if debug_config:
                     print "notice: Loading explicitly specified user configuration file:"
                     print " " + user_config
-
+
                     load_config('user-config', os.path.basename(user_config), [os.path.dirname(user_config)], True)
             else:
                 load_config('user-config', os.path.basename(user_config), user_path)
         else:
             if debug_config:
                 print "notice: User configuration file loading explicitly disabled."
-
- # We look for project-config.jam from "." upward.
- # I am not sure this is 100% right decision, we might as well check for
- # it only alonside the Jamroot file. However:
- #
- # - We need to load project-root.jam before Jamroot
- # - We probably would need to load project-root.jam even if there's no
- # Jamroot - e.g. to implement automake-style out-of-tree builds.
+
+ # We look for project-config.jam from "." upward. I am not sure this is
+ # 100% right decision, we might as well check for it only alongside the
+ # Jamroot file. However:
+ # - We need to load project-config.jam before Jamroot
+ # - We probably need to load project-config.jam even if there is no Jamroot
+ # - e.g. to implement automake-style out-of-tree builds.
     if os.path.exists("project-config.jam"):
         file = ["project-config.jam"]
     else:
@@ -359,7 +342,7 @@
                        for e in option.split(',')]
 
     for t in option_toolsets + feature_toolsets:
-
+
         # Parse toolset-version/properties.
         (toolset_version, toolset, version) = re.match("(([^-/]+)-?([^/]+)?)/?.*", t).groups()
 
@@ -459,12 +442,11 @@
 
 def main_real():
 
- global debug_config, legacy_ignore_config, out_xml
+ global debug_config, out_xml
 
     debug_config = "--debug-configuration" in sys.argv
- legacy_ignore_config = "--ignore_config" in sys.argv
     out_xml = any(re.match("^--out-xml=(.*)$", a) for a in sys.argv)
-
+
     engine = Engine()
 
     global_build_dir = option.get("build-dir")
@@ -485,23 +467,20 @@
 
     load_configuration_files()
 
- extra_properties = []
- # Note that this causes --toolset options to be ignored if --ignore-config
- # is specified.
- if not legacy_ignore_config:
- extra_properties = process_explicit_toolset_requests()
-
- # We always load project in "." so that 'use-project' directives have any
- # chance of being seen. Otherwise, we would not be able to refer to
- # subprojects using target ids.
+ # Load explicitly specified toolset modules.
+ extra_properties = process_explicit_toolset_requests()
+
+ # Load the actual project build script modules. We always load the project
+ # in the current folder so 'use-project' directives have any chance of
+ # being seen. Otherwise, we would not be able to refer to subprojects using
+ # target ids.
     current_project = None
     projects = get_manager().projects()
     if projects.find(".", "."):
         current_project = projects.target(projects.load("."))
 
- # In case there are no toolsets currently defined makes the build run using
- # the default toolset.
- if not legacy_ignore_config and not feature.values("toolset"):
+ # Load the default toolset module if no other has already been specified.
+ if not feature.values("toolset"):
 
         dt = default_toolset
         dtv = None
@@ -511,11 +490,11 @@
             dt = "gcc"
             if os.name == 'nt':
                 dt = "msvc"
- # FIXME:
+ # FIXME:
             #else if [ os.name ] = MACOSX
             #{
             # default-toolset = darwin ;
- #}
+ #}
 
         print "warning: No toolsets are configured."
         print "warning: Configuring default toolset '%s'." % dt
@@ -594,13 +573,13 @@
         targets = [projects.target(projects.module_name("."))]
 
     # FIXME: put this BACK.
-
- ## if [ option.get dump-generators : : true ]
+
+ ## if [ option.get dump-generators : : true ]
     ## {
     ## generators.dump ;
     ## }
 
-
+
     # We wish to put config.log in the build directory corresponding
     # to Jamroot, so that the location does not differ depending on
     # directory where we do build. The amount of indirection necessary
@@ -622,7 +601,7 @@
     # and any of their dependants.
     for p in expanded:
         manager.set_command_line_free_features(property_set.create(p.free()))
-
+
         for t in targets:
             try:
                 g = t.generate(p)
@@ -631,7 +610,7 @@
                 virtual_targets.extend(g.targets())
             except ExceptionWithUserContext, e:
                 e.report()
- except Exception:
+ except Exception:
                 raise
 
     # Convert collected virtual targets into actual raw Jam targets.
@@ -812,7 +791,7 @@
 ## __ACTION_RULE__ = build-system.out-xml.collect
 ## [ modules.peek build-system : .out-xml ] ;
 ## }
-
+
 ## IMPORT
 ## build-system :
 ## out-xml.collect
@@ -826,7 +805,7 @@
     j = option.get("jobs")
     if j:
         bjam.call("set-variable", PARALLELISM, j)
-
+
     k = option.get("keep-going", "true", "true")
     if k in ["on", "yes", "true"]:
         bjam.call("set-variable", "KEEP_GOING", "1")
@@ -835,7 +814,7 @@
     else:
         print "error: Invalid value for the --keep-going option"
         sys.exit()
-
+
     # The 'all' pseudo target is not strictly needed expect in the case when we
     # use it below but people often assume they always have this target
     # available and do not declare it themselves before use which may cause
@@ -872,7 +851,7 @@
         if post_build_hook:
             post_build_hook(ok)
         # Prevent automatic update of the 'all' target, now that
- # we have explicitly updated what we wanted.
+ # we have explicitly updated what we wanted.
         bjam.call("UPDATE")
 
     if manager.errors().count() == 0:

Modified: branches/release/tools/build/v2/contrib/boost.jam
==============================================================================
--- branches/release/tools/build/v2/contrib/boost.jam (original)
+++ branches/release/tools/build/v2/contrib/boost.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,65 +1,60 @@
-# $Id$
-# Copyright 2008 Roland Schwarz
+# Copyright 2008 - 2013 Roland Schwarz
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Boost library support module.
-#
-# This module allows to use the boost library from boost-build projects.
-# The location of a boost source tree or the path to a pre-built
-# version of the library can be configured from either site-config.jam
-# or user-config.jam. If no location is configured the module looks for
-# a BOOST_ROOT environment variable, which should point to a boost source
-# tree. As a last resort it tries to use pre-built libraries from the standard
-# search path of the compiler.
 #
-# If the location to a source tree is known, the module can be configured
-# from the *-config.jam files:
+# This module allows to use the boost library from boost-build projects. The
+# location of a boost source tree or the path to a pre-built version of the
+# library can be configured from either site-config.jam or user-config.jam. If
+# no location is configured the module looks for a BOOST_ROOT environment
+# variable, which should point to a boost source tree. As a last resort it tries
+# to use pre-built libraries from the standard search path of the compiler.
+#
+# If the location to a source tree is known, the module can be configured from
+# the *-config.jam files:
 #
 # using boost : 1.35 : <root>/path-to-boost-root ;
 #
 # If the location to a pre-built version is known:
 #
-# using boost : 1.34
-# : <include>/usr/local/include/boost_1_34
+# using boost : 1.34
+# : <include>/usr/local/include/boost_1_34
 # <library>/usr/local/lib
 # ;
 #
 # It is legal to configure more than one boost library version in the config
-# files. The version identifier is used to disambiguate between them.
-# The first configured version becomes the default.
+# files. The version identifier is used to disambiguate between them. The first
+# configured version becomes the default.
 #
-# To use a boost library you need to put a 'use' statement into your
-# Jamfile:
+# To use a boost library you need to put a 'use' statement into your Jamfile:
 #
 # import boost ;
 #
 # boost.use-project 1.35 ;
 #
-# If you don't care about a specific version you just can omit the version
+# If you do not care about a specific version you just can omit the version
 # part, in which case the default is picked up:
 #
 # boost.use-project ;
 #
-# The library can be referenced with the project identifier '/boost'. To
+# The library can be referenced with the project identifier '/boost'. To
 # reference the program_options you would specify:
 #
 # exe myexe : mysrc.cpp : <library>/boost//program_options ;
 #
-# Note that the requirements are automatically transformed into suitable
-# tags to find the correct pre-built library.
+# Note that the requirements are automatically transformed into suitable tags to
+# find the correct pre-built library.
 #
 
+import common ;
 import modules ;
-import errors ;
+import numbers ;
 import project ;
-import string ;
-import toolset ;
 import property-set ;
 import regex ;
-import common ;
-import option ;
-import numbers ;
+import toolset ;
 
 .boost.auto_config = [ property-set.create <layout>system ] ;
 
@@ -70,36 +65,35 @@
 
 # Configuration of the boost library to use.
 #
-# This can either be a boost source tree or
-# pre-built libraries. The 'version' parameter must be a valid boost
-# version number, e.g. 1.35, if specifying a pre-built version with
-# versioned layout. It may be a symbolic name, e.g. 'trunk' if specifying
-# a source tree. The options are specified as named parameters (like
-# properties). The following paramters are available:
-#
-# <root>/path-to-boost-root: Specify a source tree.
-#
-# <include>/path-to-include: The include directory to search.
-#
-# <library>/path-to-library: The library directory to search.
-#
-# <layout>system or <layout>versioned.
-#
-# <build-id>my_build_id: The custom build id to use.
+# This can either be a boost source tree or pre-built libraries. The 'version'
+# parameter must be a valid boost version number, e.g. 1.35, if specifying a
+# pre-built version with versioned layout. It may be a symbolic name, e.g.
+# 'trunk' if specifying a source tree. The options are specified as named
+# parameters (like properties). The following paramters are available:
+#
+# <root>/path-to-boost-root : Specify a source tree.
+# <include>/path-to-include : The include directory to search.
+# <library>/path-to-library : The library directory to search.
+# <layout>system or <layout>versioned : Built library layout.
+# <build-id>my_build_id : The custom build id to use.
 #
-rule init
-(
+rule init
+(
     version # Version identifier.
     : options * # Set the option properties.
 )
 {
- if $(.boost.$(version)) {
- errors.user-error
- "Boost " $(version) "already configured." ;
+ if $(.boost.$(version))
+ {
+ import errors ;
+ errors.user-error Boost $(version) already configured. ;
     }
- else {
- if $(.debug-configuration) {
- if ! $(.boost_default) {
+ else
+ {
+ if $(.debug-configuration)
+ {
+ if ! $(.boost_default)
+ {
                 echo notice: configuring default boost library $(version) ;
             }
             echo notice: configuring boost library $(version) ;
@@ -111,81 +105,97 @@
 
 # Use a certain version of the library.
 #
-# The use-project rule causes the module to define a boost project of
-# searchable pre-built boost libraries, or references a source tree
-# of the boost library. If the 'version' parameter is omitted either
-# the configured default (first in config files) is used or an auto
-# configuration will be attempted.
-#
-rule use-project
-(
+# The use-project rule causes the module to define a boost project of searchable
+# pre-built boost libraries, or references a source tree of the boost library.
+# If the 'version' parameter is omitted either the configured default (first in
+# config files) is used or an auto configuration will be attempted.
+#
+rule use-project
+(
     version ? # The version of the library to use.
 )
 {
     project.push-current [ project.current ] ;
     version ?= $(.boost_default) ;
     version ?= auto_config ;
-
- if $(.initialized) {
- if $(.initialized) != $(version) {
- errors.user-error
- "Attempt to use" $(__name__) "with different parameters" ;
+
+ if $(.initialized)
+ {
+ if $(.initialized) != $(version)
+ {
+ import errors ;
+ errors.user-error Attempt to use $(__name__) with different
+ parameters. ;
         }
     }
- else {
- if $(.boost.$(version)) {
+ else
+ {
+ if $(.boost.$(version))
+ {
             local opt = $(.boost.$(version)) ;
             local root = [ $(opt).get <root> ] ;
             local inc = [ $(opt).get <include> ] ;
             local lib = [ $(opt).get <library> ] ;
-
- if $(.debug-configuration) {
+
+ if $(.debug-configuration)
+ {
                 echo notice: using boost library $(version) [ $(opt).raw ] ;
             }
-
+
             .layout = [ $(opt).get <layout> ] ;
             .layout ?= versioned ;
             .build_id = [ $(opt).get <build-id> ] ;
             .version_tag = [ regex.replace $(version) "[*\\/:.\"\' ]" "_" ] ;
             .initialized = $(version) ;
 
- if ( $(root) && $(inc) )
+ if ( $(root) && $(inc) )
                 || ( $(root) && $(lib) )
                 || ( $(lib) && ! $(inc) )
- || ( ! $(lib) && $(inc) ) {
- errors.user-error
- "Ambiguous parameters,"
- "use either <root> or <inlude> with <library>." ;
+ || ( ! $(lib) && $(inc) )
+ {
+ import errors ;
+ errors.user-error Ambiguous parameters, use either <root> or
+ <include> with <library>. ;
             }
- else if ! $(root) && ! $(inc) {
+ else if ! $(root) && ! $(inc)
+ {
                 root = [ modules.peek : BOOST_ROOT ] ;
             }
 
             local prj = [ project.current ] ;
             local mod = [ $(prj).project-module ] ;
 
- if $(root) {
+ if $(root)
+ {
                 modules.call-in $(mod) : use-project boost : $(root) ;
             }
- else {
+ else
+ {
                 project.initialize $(__name__) ;
- # It is possible to overide the setup of the searched
- # libraries per version. The (unlikely) tag 0.0.1 is
- # meant as an example template only.
- switch $(version) {
+ # It is possible to overide the setup of the searched libraries
+ # per version. The (unlikely) 0.0.1 tag is meant as an example
+ # template only.
+ switch $(version)
+ {
                     case 0.0.1 : boost_0_0_1 $(inc) $(lib) ;
- case * : boost_std $(inc) $(lib) ;
+ case * : boost_std $(inc) $(lib) ;
                 }
             }
         }
- else {
- errors.user-error
- "Reference to unconfigured boost version." ;
+ else
+ {
+ import errors ;
+ errors.user-error Reference to unconfigured boost version. ;
         }
     }
     project.pop-current ;
 }
 
+local rule boost_lib_std ( id : shared-lib-define )
+{
+ lib $(id) : : : : <link>shared:<define>$(shared-lib-define) ;
+}
+
 rule boost_std ( inc ? lib ? )
 {
 # The default definitions for pre-built libraries.
@@ -196,66 +206,44 @@
         ;
 
     alias headers ;
- lib date_time : : : :
- <link>shared:<define>BOOST_DATE_TIME_DYN_LINK ;
- lib filesystem : : : :
- <link>shared:<define>BOOST_FILE_SYSTEM_DYN_LINK ;
- lib graph : : : :
- <link>shared:<define>BOOST_GRAPH_DYN_LINK ;
- lib graph_parallel : : : :
- <link>shared:<define>BOOST_GRAPH_DYN_LINK ;
- lib iostreams : : : :
- <link>shared:<define>BOOST_IOSTREAMS_DYN_LINK ;
- lib math_tr1 : : : :
- <link>shared:<define>BOOST_MATH_TR1_DYN_LINK ;
- lib math_tr1f : : : :
- <link>shared:<define>BOOST_MATH_TR1_DYN_LINK ;
- lib math_tr1l : : : :
- <link>shared:<define>BOOST_MATH_TR1_DYN_LINK ;
- lib math_c99 : : : :
- <link>shared:<define>BOOST_MATH_TR1_DYN_LINK ;
- lib math_c99f : : : :
- <link>shared:<define>BOOST_MATH_TR1_DYN_LINK ;
- lib math_c99l : : : :
- <link>shared:<define>BOOST_MATH_TR1_DYN_LINK ;
- lib mpi : : : :
- <link>shared:<define>BOOST_MPI_DYN_LINK ;
- lib program_options : : : :
- <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK ;
- lib python : : : :
- <link>shared:<define>BOOST_PYTHON_DYN_LINK ;
- lib random : : : :
- <link>shared:<define>BOOST_RANDOM_DYN_LINK ;
- lib regex : : : :
- <link>shared:<define>BOOST_REGEX_DYN_LINK ;
- lib serialization : : : :
- <link>shared:<define>BOOST_SERIALIZATION_DYN_LINK ;
- lib wserialization : : : :
- <link>shared:<define>BOOST_SERIALIZATION_DYN_LINK ;
- lib signals : : : :
- <link>shared:<define>BOOST_SIGNALS_DYN_LINK ;
- lib system : : : :
- <link>shared:<define>BOOST_SYSTEM_DYN_LINK ;
- lib unit_test_framework : : : :
- <link>shared:<define>BOOST_TEST_DYN_LINK ;
- lib prg_exec_monitor : : : :
- <link>shared:<define>BOOST_TEST_DYN_LINK ;
- lib test_exec_monitor : : : :
- <link>shared:<define>BOOST_TEST_DYN_LINK ;
- lib thread : : : :
- <link>shared:<define>BOOST_THREAD_DYN_DLL ;
- lib wave : : : :
- <link>shared:<define>BOOST_WAVE_DYN_LINK ;
+ boost_lib_std chrono : BOOST_CHRONO_DYN_LINK ;
+ boost_lib_std date_time : BOOST_DATE_TIME_DYN_LINK ;
+ boost_lib_std filesystem : BOOST_FILE_SYSTEM_DYN_LINK ;
+ boost_lib_std graph : BOOST_GRAPH_DYN_LINK ;
+ boost_lib_std graph_parallel : BOOST_GRAPH_DYN_LINK ;
+ boost_lib_std iostreams : BOOST_IOSTREAMS_DYN_LINK ;
+ boost_lib_std locale : BOOST_LOCALE_DYN_LINK ;
+ boost_lib_std math_tr1 : BOOST_MATH_TR1_DYN_LINK ;
+ boost_lib_std math_tr1f : BOOST_MATH_TR1_DYN_LINK ;
+ boost_lib_std math_tr1l : BOOST_MATH_TR1_DYN_LINK ;
+ boost_lib_std math_c99 : BOOST_MATH_TR1_DYN_LINK ;
+ boost_lib_std math_c99f : BOOST_MATH_TR1_DYN_LINK ;
+ boost_lib_std math_c99l : BOOST_MATH_TR1_DYN_LINK ;
+ boost_lib_std mpi : BOOST_MPI_DYN_LINK ;
+ boost_lib_std program_options : BOOST_PROGRAM_OPTIONS_DYN_LINK ;
+ boost_lib_std python : BOOST_PYTHON_DYN_LINK ;
+ boost_lib_std python3 : BOOST_PYTHON_DYN_LINK ;
+ boost_lib_std random : BOOST_RANDOM_DYN_LINK ;
+ boost_lib_std regex : BOOST_REGEX_DYN_LINK ;
+ boost_lib_std serialization : BOOST_SERIALIZATION_DYN_LINK ;
+ boost_lib_std wserialization : BOOST_SERIALIZATION_DYN_LINK ;
+ boost_lib_std signals : BOOST_SIGNALS_DYN_LINK ;
+ boost_lib_std system : BOOST_SYSTEM_DYN_LINK ;
+ boost_lib_std unit_test_framework : BOOST_TEST_DYN_LINK ;
+ boost_lib_std prg_exec_monitor : BOOST_TEST_DYN_LINK ;
+ boost_lib_std test_exec_monitor : BOOST_TEST_DYN_LINK ;
+ boost_lib_std thread : BOOST_THREAD_DYN_DLL ;
+ boost_lib_std wave : BOOST_WAVE_DYN_LINK ;
 }
 
+# Example placeholder for rules defining Boost library project & library targets
+# for a specific Boost library version. Copy under a different name and model
+# after the boost_std rule. Please note that it is also possible to have a per
+# version taging rule in case the tagging algorithm changes between versions.
+#
 rule boost_0_0_1 ( inc ? lib ? )
 {
     echo "You are trying to use an example placeholder for boost libs." ;
- # Copy this template to another place (in the file boost.jam)
- # and define a project and libraries modelled after the
- # boost_std rule. Please note that it is also possible to have
- # a per version taging rule in case they are different between
- # versions.
 }
 
 rule tag_std ( name : type ? : property-set )
@@ -290,7 +278,8 @@
     }
     else
     {
- errors.error "Missing layout" ;
+ import errors ;
+ errors.error Missing layout. ;
     }
 
     return $(result) ;
@@ -298,24 +287,18 @@
 
 rule tag_system ( name : type ? : property-set )
 {
- return [ common.format-name
- <base>
- -$(.build_id)
- : $(name) : $(type) : $(property-set) ] ;
+ return [ common.format-name <base> -$(.build_id) : $(name) : $(type) :
+ $(property-set) ] ;
 }
 
 rule tag_tagged ( name : type ? : property-set )
 {
- return [ common.format-name
- <base> <threading> <runtime>
- -$(.build_id)
- : $(name) : $(type) : $(property-set) ] ;
+ return [ common.format-name <base> <threading> <runtime> -$(.build_id) :
+ $(name) : $(type) : $(property-set) ] ;
 }
 
 rule tag_versioned ( name : type ? : property-set )
 {
- return [ common.format-name
- <base> <toolset> <threading> <runtime> -$(.version_tag)
- -$(.build_id)
- : $(name) : $(type) : $(property-set) ] ;
+ return [ common.format-name <base> <toolset> <threading> <runtime>
+ -$(.version_tag) -$(.build_id) : $(name) : $(type) : $(property-set) ] ;
 }

Modified: branches/release/tools/build/v2/doc/bjam.qbk
==============================================================================
--- branches/release/tools/build/v2/doc/bjam.qbk (original)
+++ branches/release/tools/build/v2/doc/bjam.qbk 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,7 +7,7 @@
     [id jam]
     [dirname jam]
     [purpose
- Jam is a make(1) replacement that makes building simple things simple
+ Jam is a make(1) replacement that makes building simple things simple
         and building complicated things manageable.
     ]
     [license
@@ -44,9 +44,9 @@
 [template lines[items]'''<simplelist type='vert' columns='1'>'''[items]'''</simplelist>''']
 [template line[text]'''<member>'''[text]'''</member>''']
 
-[section:building Building BJam]
+[section:building Building B2]
 
-Installing =BJam= after building it is simply a matter of copying the
+Installing =B2= after building it is simply a matter of copying the
 generated executables someplace in your =PATH=. For building the executables
 there are a set of =build= bootstrap scripts to accomodate particular
 environments. The scripts take one optional argument, the name of the toolset
@@ -71,7 +71,7 @@
 sh ./build.sh
 ]
 
-For the Boost.Jam source included with the Boost distribution the /jam source location/ is =BOOST_ROOT/tools/jam/src=.
+For the Boost.Jam source included with the Boost distribution the /jam source location/ is =BOOST_ROOT/tools/build/v2/engine=.
 
 If the scripts fail to detect an appropriate toolset to build with your particular toolset may not be auto-detectable. In that case, you can specify the toolset as the first argument, this assumes that the toolset is readily available in the =PATH=.
 
@@ -192,10 +192,10 @@
             [li Common install location: "=%ProgramFiles%\Microsoft Visual Studio 8="]
             [li =CL.EXE= in =PATH=]
             ]
-
+
     Notes:
         [list
- [li If =VCVARSALL.BAT= is called to set up the toolset, it is passed all the extra arguments, see below for what those arguments are. This can be used to build, for example, a Win64 specific version of =bjam=. Consult the VisualStudio documentation for what the possible argument values to the =VCVARSALL.BAT= are.]
+ [li If =VCVARSALL.BAT= is called to set up the toolset, it is passed all the extra arguments, see below for what those arguments are. This can be used to build, for example, a Win64 specific version of =b2=. Consult the VisualStudio documentation for what the possible argument values to the =VCVARSALL.BAT= are.]
             ]
         ]
 ]
@@ -334,7 +334,7 @@
 
 ]
 
-The built executables are placed in a subdirectory specific to your platform. For example, in Linux running on an Intel x86 compatible chip, the executables are placed in: "=bin.linuxx86=". The =bjam[.exe]= executable can be used to invoke Boost.Build.
+The built executables are placed in a subdirectory specific to your platform. For example, in Linux running on an Intel x86 compatible chip, the executables are placed in: "=bin.linuxx86=". The =b2[.exe]= executable can be used to invoke Boost.Build.
 
 The build scripts support additional invocation arguments for use by developers of Boost.Jam and for additional setup of the toolset. The extra arguments come after the toolset:
 
@@ -346,7 +346,7 @@
 /build/ \[/toolset/\] \[/setup/\*\] \[--/option/+ /target/\*\]
 ]
 
-The arguments immediately after the toolset are passed directly to the setup script of the toolset, if available and if it needs to be invoked. This allows one to configure the toolset ass needed to do non-default builds of =bjam=. For example to build a Win64 version with =vc8=. See the toolset descriptiona above for when particular toolsets support this.
+The arguments immediately after the toolset are passed directly to the setup script of the toolset, if available and if it needs to be invoked. This allows one to configure the toolset ass needed to do non-default builds of =b2=. For example to build a Win64 version with =vc8=. See the toolset descriptiona above for when particular toolsets support this.
 
 The arguments starting with the "=--option=" forms are passed to the =build.jam= script and are used to further customize what gets built. Options and targets supported by the =build.jam= script:
 
@@ -362,9 +362,9 @@
     [[[literal --with-python=/path/]]
         [Enables Python integration, given a path to the Python libraries.]]
     [[[literal --gc]]
- [Enables use of the Boehm Garbage Collector. The build will look for the Boehm-GC source in a "boehm_gc" subdirectory from the =bjam= sources.]]
+ [Enables use of the Boehm Garbage Collector. The build will look for the Boehm-GC source in a "boehm_gc" subdirectory from the =b2= sources.]]
     [[[literal --duma]]
- [Enables use of the DUMA (Detect Uintended Memory Access) debugging memory allocator. The build expects to find the DUMA source files in a "duma" subdirectory from the =bjam= sources.]]
+ [Enables use of the DUMA (Detect Uintended Memory Access) debugging memory allocator. The build expects to find the DUMA source files in a "duma" subdirectory from the =b2= sources.]]
     [[[literal --toolset-root=/path/]]
         [Indicates where the toolset used to build is located. This option is passed in by the bootstrap (=build.bat= or =build.sh=) script.]]
     [[[literal --show-locate-target]]
@@ -381,17 +381,17 @@
 
 [section:language Language]
 
-=BJam= has an interpreted, procedural language. Statements in =bjam= are rule (procedure) definitions, rule invocations, flow-of-control structures, variable assignments, and sundry language support.
+=B2= has an interpreted, procedural language. Statements in =b2= are rule (procedure) definitions, rule invocations, flow-of-control structures, variable assignments, and sundry language support.
 
 [section:lexical Lexical Features]
 
-=BJam= treats its input files as whitespace-separated tokens, with two exceptions: double quotes (") can enclose whitespace to embed it into a token, and everything between the matching curly braces ({}) in the definition of a rule action is treated as a single string. A backslash (\\) can escape a double quote, or any single whitespace character.
+=B2= treats its input files as whitespace-separated tokens, with two exceptions: double quotes (") can enclose whitespace to embed it into a token, and everything between the matching curly braces ({}) in the definition of a rule action is treated as a single string. A backslash (\\) can escape a double quote, or any single whitespace character.
 
-=BJam= requires whitespace (blanks, tabs, or newlines) to surround all tokens, including the colon (:) and semicolon (;) tokens.
+=B2= requires whitespace (blanks, tabs, or newlines) to surround all tokens, including the colon (:) and semicolon (;) tokens.
 
-=BJam= keywords (an mentioned in this document) are reserved and generally
+=B2= keywords (an mentioned in this document) are reserved and generally
 must be quoted with double quotes (") to be used as arbitrary tokens, such as
-variable or target names.
+variable or target names.
 
 Comments start with the [^#] character and extend until the end of line.
 
@@ -399,9 +399,9 @@
 
 [section:target Targets]
 
-The essential =bjam= data entity is a target. Build targets are files to be updated. Source targets are the files used in updating built targets. Built targets and source targets are collectively referred to as file targets, and frequently built targets are source targets for other built targets. Pseudotargets are symbols which represent dependencies on other targets, but which are not themselves associated with any real file.
+The essential =b2= data entity is a target. Build targets are files to be updated. Source targets are the files used in updating built targets. Built targets and source targets are collectively referred to as file targets, and frequently built targets are source targets for other built targets. Pseudotargets are symbols representing dependencies on other targets, but which are not themselves associated with any real file.
 
-A file target's identifier is generally the file's name, which can be absolutely rooted, relative to the directory of =bjam='s invocation, or simply local (no directory). Most often it is the last case, and the actual file path is bound using the =$(SEARCH)= and =$(LOCATE)= special variables. See [link jam.language.variables.builtins.search SEARCH and LOCATE Variables] below. A local filename is optionally qualified with grist, a string value used to assure uniqueness. A file target with an identifier of the form /file(member)/ is a library member (usually an =ar=(1) archive on Unix).
+A file target's identifier is generally the file's name, which can be absolutely rooted, relative to the directory of =b2='s invocation, or simply local (no directory). Most often it is the last case, and the actual file path is bound using the =$(SEARCH)= and =$(LOCATE)= special variables. See [link jam.language.variables.builtins.search SEARCH and LOCATE Variables] below. A local filename is optionally qualified with grist, a string value used to assure uniqueness. A file target with an identifier of the form /file(member)/ is a library member (usually an =ar=(1) archive on Unix).
 
 [section Binding Detection]
 
@@ -419,11 +419,11 @@
 
 [section:rules Rules]
 
-The basic =bjam= language entity is called a rule. A rule is defined in two parts: the procedure and the actions. The procedure is a body of jam statements to be run when the rule is invoked; the actions are the OS shell commands to execute when updating the built targets of the rule.
+The basic =b2= language entity is called a rule. A rule is defined in two parts: the procedure and the actions. The procedure is a body of jam statements to be run when the rule is invoked; the actions are the OS shell commands to execute when updating the built targets of the rule.
 
 Rules can return values, which can be expanded into a list with "[ /rule/ /args/ ... ]". A rule's value is the value of its last statement, though only the following statements have values: 'if' (value of the leg chosen), 'switch' (value of the case chosen), set (value of the resulting variable), and 'return' (value of its arguments). Note that 'return' doesn't actually cause a return, i.e., is a no-op unless it is the last statement of the last block executed within rule body.
 
-The =bjam= statements for defining and invoking rules are as follows:
+The =b2= statements for defining and invoking rules are as follows:
 
 Define a rule's procedure, replacing any previous definition.
 
@@ -534,7 +534,7 @@
 [[=+=] [Bind to one or more unbound elements of the actual argument.]]
 ]
 
-The actual and formal arguments are checked for inconsistencies, which cause Jam to exit with an error code:
+The actual and formal arguments are checked for inconsistencies, which cause =b2= to exit with an error code:
 
 [pre
 ### argument error
@@ -553,7 +553,7 @@
 
 [section:builtins Built-in Rules]
 
-=BJam= has a growing set of built-in rules, all of which are pure procedure rules without updating actions. They are in three groups: the first builds the dependency graph; the second modifies it; and the third are just utility rules.
+=B2= has a growing set of built-in rules, all of which are pure procedure rules without updating actions. They are in three groups: the first builds the dependency graph; the second modifies it; and the third are just utility rules.
 
 [section Dependency Building]
 
@@ -588,7 +588,7 @@
 
 [section Modifying Binding]
 
-The six rules =ALWAYS=, =LEAVES=, =NOCARE=, =NOTFILE=, =NOUPDATE=, and =TEMPORARY= modify the dependency graph so that =bjam= treats the targets differently during its target binding phase. See Binding above. Normally, =bjam= updates a target if it is missing, if its filesystem modification time is older than any of its dependencies (recursively), or if any of its dependencies are being updated. This basic behavior can be changed by invoking the following rules:
+The six rules =ALWAYS=, =LEAVES=, =NOCARE=, =NOTFILE=, =NOUPDATE=, and =TEMPORARY= modify the dependency graph so that =b2= treats the targets differently during its target binding phase. See Binding above. Normally, =b2= updates a target if it is missing, if its filesystem modification time is older than any of its dependencies (recursively), or if any of its dependencies are being updated. This basic behavior can be changed by invoking the following rules:
 
 [section =ALWAYS= ]
 
@@ -616,7 +616,7 @@
 rule NOCARE ( /targets/ * )
 ]
 
-Causes =bjam= to ignore /targets/ that neither can be found nor have updating actions to build them. Normally for such targets =bjam= issues a warning and then skips other targets that depend on these missing targets. The =HdrRule= in =Jambase= uses =NOCARE= on the header file names found during header file scanning, to let =bjam= know that the included files may not exist. For example, if an `#include` is within an `#ifdef`, the included file may not actually be around.
+Causes =b2= to ignore /targets/ that neither can be found nor have updating actions to build them. Normally for such targets =b2= issues a warning and then skips other targets that depend on these missing targets. The =HdrRule= in =Jambase= uses =NOCARE= on the header file names found during header file scanning, to let =b2= know that the included files may not exist. For example, if an `#include` is within an `#ifdef`, the included file may not actually be around.
 
 [warning For targets with build actions: if their build actions exit with a nonzero return code, dependent targets will still be built.]
 
@@ -628,7 +628,7 @@
 rule NOTFILE ( /targets/ * )
 ]
 
-Marks /targets/ as pseudotargets and not real files. No timestamp is checked, and so the actions on such a target are only executed if the target's dependencies are updated, or if the target is also marked with =ALWAYS=. The default =bjam= target "=all=" is a pseudotarget. In =Jambase=, =NOTFILE= is used to define several addition convenient pseudotargets.
+Marks /targets/ as pseudotargets and not real files. No timestamp is checked, and so the actions on such a target are only executed if the target's dependencies are updated, or if the target is also marked with =ALWAYS=. The default =b2= target "=all=" is a pseudotarget. In =Jambase=, =NOTFILE= is used to define several addition convenient pseudotargets.
 
 [endsect]
 
@@ -648,7 +648,7 @@
 rule TEMPORARY ( /targets/ * )
 ]
 
-Marks /targets/ as temporary, allowing them to be removed after other targets that depend upon them have been updated. If a =TEMPORARY= target is missing, =bjam= uses the timestamp of the target's parent. =Jambase= uses =TEMPORARY= to mark object files that are archived in a library after they are built, so that they can be deleted after they are archived.
+Marks /targets/ as temporary, allowing them to be removed after other targets that depend upon them have been updated. If a =TEMPORARY= target is missing, =b2= uses the timestamp of the target's parent. =Jambase= uses =TEMPORARY= to mark object files that are archived in a library after they are built, so that they can be deleted after they are archived.
 
 [endsect]
 
@@ -673,7 +673,7 @@
 rule RMOLD ( /targets/ * )
 ]
 
-=BJam= removes any target files that may exist on disk when the rule used to build those targets fails. However, targets whose dependencies fail to build are not removed by default. The =RMOLD= rule causes its arguments to be removed if any of their dependencies fail to build.
+=B2= removes any target files that may exist on disk when the rule used to build those targets fails. However, targets whose dependencies fail to build are not removed by default. The =RMOLD= rule causes its arguments to be removed if any of their dependencies fail to build.
 
 [endsect]
 
@@ -683,7 +683,7 @@
 rule ISFILE ( /targets/ * )
 ]
 
-=ISFILE= marks targets as required to be files. This changes the way =bjam= searches for the target such that it ignores mathes for file system items that are not file, like directories. This makes it possible to avoid `#include "exception"` matching if one happens to have a directory named exception in the header search path.
+=ISFILE= marks targets as required to be files. This changes the way =b2= searches for the target such that it ignores matches for file system items that are not files, like directories. This makes it possible to avoid `#include "exception"` matching if one happens to have a directory named exception in the header search path.
 
 [warning This is currently not fully implemented.]
 
@@ -693,7 +693,7 @@
 
 [section Utility]
 
-The two rules =ECHO= and =EXIT= are utility rules, used only in =bjam='s parsing phase.
+The two rules =ECHO= and =EXIT= are utility rules, used only in =b2='s parsing phase.
 
 [section =ECHO= ]
 
@@ -713,7 +713,7 @@
 
 Blurts out the /message/ to stdout and then exits with a failure status if no /result-value/ is given, otherwise it exits with the given /result-value/.
 
-"=Echo=", "=echo=", "=Exit=", and "=exit=" are accepted as aliases for =ECHO= and =EXIT=, since it is hard to tell that these are built-in rules and not part of the language, like "=include=".
+"=Echo=", "=echo=", "=Exit=", and "=exit=" are accepted as aliases for =ECHO= and =EXIT=, since it is hard to tell that these are built-in rules and not part of the language, like "=include=".
 
 [endsect]
 
@@ -727,7 +727,7 @@
 
 Using the same wildcards as for the patterns in the switch statement. It is invoked by being used as an argument to a rule invocation inside of "=[ ]=". For example: "[^FILES = \[ GLOB dir1 dir2 : *.c *.h \]]" sets =FILES= to the list of C source and header files in =dir1= and =dir2=. The resulting filenames are the full pathnames, including the directory, but the pattern is applied only to the file name without the directory.
 
-If /downcase-opt/ is supplied, filenames are converted to all-lowercase before matching against the pattern; you can use this to do case-insensitive matching using lowercase patterns. The paths returned will still have mixed case if the OS supplies them. On Windows NT and Cygwin, filenames are always downcased before matching.
+If /downcase-opt/ is supplied, filenames are converted to all-lowercase before matching against the pattern; you can use this to do case-insensitive matching using lowercase patterns. The paths returned will still have mixed case if the OS supplies them. On Windows NT and Cygwin, filenames are always downcased before matching.
 
 [endsect]
 
@@ -739,7 +739,7 @@
 rule MATCH ( /regexps/ + : /list/ * )
 ]
 
-Matches the =egrep=(1) style regular expressions /regexps/ against the strings in /list/. The result is the concatenation of matching =()= subexpressions for each string in /list/, and for each regular expression in /regexps/. Only useful within the "=[ ]=" construct, to change the result into a list.
+Matches the =egrep=(1) style regular expressions /regexps/ against the strings in /list/. The result is a list of matching =()= subexpressions for each string in /list/, and for each regular expression in /regexps/.
 
 [endsect]
 
@@ -814,7 +814,7 @@
 If '/result-type/' is not recognized, or requested data cannot be retrieved, the rule returns an empty list.
 Example:
 
-[pre
+[pre
 local key = "HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\App Paths" ;
 local subkeys = \[ W32_GETREGNAMES "$(key)" : subkeys \] ;
 for local subkey in $(subkeys)
@@ -927,7 +927,7 @@
 
 [section Flow-of-Control]
 
-=BJam= has several simple flow-of-control statements:
+=B2= has several simple flow-of-control statements:
 
 [pre
 for /var/ in /list/ { /statements/ }
@@ -986,9 +986,9 @@
 include /file/ ;
 ]
 
-Causes =bjam= to read the named /file/. The /file/ is bound like a regular target (see Binding above) but unlike a regular target the include /file/ cannot be built.
+Causes =b2= to read the named /file/. The /file/ is bound like a regular target (see Binding above) but unlike a regular target the include /file/ cannot be built.
 
-The include /file/ is inserted into the input stream during the parsing phase. The primary input file and all the included file(s) are treated as a single file; that is, jam infers no scope boundaries from included files.
+The include /file/ is inserted into the input stream during the parsing phase. The primary input file and all the included file(s) are treated as a single file; that is, =b2= infers no scope boundaries from included files.
 
 [pre
 local /vars/ \[ = /values/ \] ;
@@ -1036,13 +1036,13 @@
 while /cond/ { /statements/ }
 ]
 
-Repeatedly execute /statements/ while /cond/ remains true upon entry. (See the description of /cond/ expression syntax under if, above).
+Repeatedly execute /statements/ while /cond/ remains true upon entry. (See the description of /cond/ expression syntax under if, above).
 
 [endsect]
 
 [section Variables]
 
-=BJam= variables are lists of zero or more elements, with each element being a string value. An undefined variable is indistinguishable from a variable with an empty list, however, a defined variable may have one more elements which are null strings. All variables are referenced as [^$(/variable/)].
+=B2= variables are lists of zero or more elements, with each element being a string value. An undefined variable is indistinguishable from a variable with an empty list, however, a defined variable may have one more elements which are null strings. All variables are referenced as [^$(/variable/)].
 
 Variables are either global or target-specific. In the latter case, the variable takes on the given value only during the updating of the specific target.
 
@@ -1061,11 +1061,11 @@
 
 Variables referenced in updating commands will be replaced with their values; target-specific values take precedence over global values. Variables passed as arguments (=$(1)= and =$(2)=) to actions are replaced with their bound values; the "=bind=" modifier can be used on actions to cause other variables to be replaced with bound values. See Action Modifiers above.
 
-=BJam= variables are not re-exported to the environment of the shell that executes the updating actions, but the updating actions can reference =bjam= variables with [^$(/variable/)].
+=B2= variables are not re-exported to the environment of the shell that executes the updating actions, but the updating actions can reference =b2= variables with [^$(/variable/)].
 
 [section:expansion Variable Expansion]
 
-During parsing, =bjam= performs variable expansion on each token that is not a keyword or rule name. Such tokens with embedded variable references are replaced with zero or more tokens. Variable references are of the form [^$(/v/)] or [^$(/vm/)], where ['v] is the variable name, and ['m] are optional modifiers.
+During parsing, =b2= performs variable expansion on each token that is not a keyword or rule name. Such tokens with embedded variable references are replaced with zero or more tokens. Variable references are of the form [^$(/v/)] or [^$(/vm/)], where ['v] is the variable name, and ['m] are optional modifiers.
 
 Variable expansion in a rule's actions is similar to variable expansion in statements, except that the action string is tokenized at whitespace regardless of quoting.
 
@@ -1138,20 +1138,20 @@
 
 [[[^:T]]
  [Converts all back-slashes ("\\") to forward slashes ("/"). For example
-``
+``
  x = "C:\\Program Files\\Borland" ; ECHO $(x:T) ;
 ``
 prints [^"C:/Program Files/Borland"]
 ]]
 
 [[[^:W]]
- [When invoking Windows-based tools from [@http://www.cygwin.com/ Cygwin]
- it can be important to pass them true windows-style paths. The =:W=
+ [When invoking Windows-based tools from [@http://www.cygwin.com/ Cygwin]
+ it can be important to pass them true windows-style paths. The =:W=
   modifier, *under Cygwin only*, turns a cygwin path into a Win32 path using
  the [@http://www.cygwin.com/cygwin-api/func-cygwin-conv-to-win32-path.html
  =cygwin_conv_to_win32_path=] function. On other platforms, the string is
  unchanged. For example
-``
+``
  x = "/cygdrive/c/Program Files/Borland" ; ECHO $(x:W) ;
 ``
 prints [^"C:\\Program Files\\Borland"] on Cygwin
@@ -1208,7 +1208,7 @@
 
 [section:atfile Generated File Expansion]
 
-During expansion of expressions =bjam= also looks for subexpressions of the form
+During expansion of expressions =b2= also looks for subexpressions of the form
 =@(filename:E=filecontents)= and replaces the expression with =filename= after
 creating the given file with the contents set to =filecontents=. This is useful
 for creating compiler response files, and other "internal" files. The expansion
@@ -1219,7 +1219,7 @@
 
 [section:builtins Built-in Variables]
 
-This section discusses variables that have special meaning to =bjam=. All of
+This section discusses variables that have special meaning to =b2=. All of
 these must be defined or used in the global module -- using those variables
 inside a named module will not have the desired effect.
 See [link jam.language.modules Modules].
@@ -1234,9 +1234,9 @@
 
 * If =$(LOCATE)= is set then the target is bound relative to the first directory in =$(LOCATE)=. Only the first element is used for binding.
 * If =$(SEARCH)= is set then the target is bound to the first directory in =$(SEARCH)= where the target file already exists.
-* If the =$(SEARCH)= search fails, the target is bound relative to the current directory anyhow.
+* If the =$(SEARCH)= search fails, the target is bound relative to the current directory anyhow.
 
-Both =$(SEARCH)= and =$(LOCATE)= should be set target-specific and not globally. If they were set globally, =bjam= would use the same paths for all file binding, which is not likely to produce sane results. When writing your own rules, especially ones not built upon those in Jambase, you may need to set =$(SEARCH)= or =$(LOCATE)= directly. Almost all of the rules defined in Jambase set =$(SEARCH)= and =$(LOCATE)= to sensible values for sources they are looking for and targets they create, respectively.
+Both =$(SEARCH)= and =$(LOCATE)= should be set target-specific and not globally. If they were set globally, =b2= would use the same paths for all file binding, which is not likely to produce sane results. When writing your own rules, especially ones not built upon those in Jambase, you may need to set =$(SEARCH)= or =$(LOCATE)= directly. Almost all of the rules defined in Jambase set =$(SEARCH)= and =$(LOCATE)= to sensible values for sources they are looking for and targets they create, respectively.
 
 [endsect]
 
@@ -1247,14 +1247,14 @@
 inclusion statements in source files. =Jambase= uses =$(HDRPATTERN)= as the
 pattern for =$(HDRSCAN)=. =$(HDRRULE)= is the name of a rule to invoke with
 the results of the scan: the scanned file is the target, the found files are
-the sources. This is the only place where =bjam= invokes a rule through a
+the sources. This is the only place where =b2= invokes a rule through a
 variable setting.
 
 Both =$(HDRSCAN)= and =$(HDRRULE)= must be set for header file scanning to take place, and they should be set target-specific and not globally. If they were set globally, all files, including executables and libraries, would be scanned for header file include statements.
 
-The scanning for header file inclusions is not exact, but it is at least dynamic, so there is no need to run something like =makedepend(GNU)= to create a static dependency file. The scanning mechanism errs on the side of inclusion (i.e., it is more likely to return filenames that are not actually used by the compiler than to miss include files) because it can't tell if `#include` lines are inside `#ifdefs` or other conditional logic. In =Jambase=, =HdrRule= applies the =NOCARE= rule to each header file found during scanning so that if the file isn't present yet doesn't cause the compilation to fail, =bjam= won't care.
+The scanning for header file inclusions is not exact, but it is at least dynamic, so there is no need to run something like =makedepend(GNU)= to create a static dependency file. The scanning mechanism errs on the side of inclusion (i.e., it is more likely to return filenames that are not actually used by the compiler than to miss include files) because it can't tell if `#include` lines are inside `#ifdefs` or other conditional logic. In =Jambase=, =HdrRule= applies the =NOCARE= rule to each header file found during scanning so that if the file isn't present yet doesn't cause the compilation to fail, =b2= won't care.
 
-Also, scanning for regular expressions only works where the included file name is literally in the source file. It can't handle languages that allow including files using variable names (as the =Jam= language itself does).
+Also, scanning for regular expressions only works where the included file name is literally in the source file. It can't handle languages that allow including files using variable names (as the =Jam= language itself does).
 
 [endsect]
 
@@ -1292,9 +1292,9 @@
 [section Jam Version]
 
 [variablelist
-[[=JAMDATE=] [Time and date at =bjam= start-up as an ISO-8601 UTC value.]]
+[[=JAMDATE=] [Time and date at =b2= start-up as an ISO-8601 UTC value.]]
 [[=JAMUNAME=] [Ouput of uname(1) command (Unix only)]]
-[[=JAMVERSION=] [=bjam= version, currently ":version:"]]
+[[=JAMVERSION=] [=b2= version, currently ":version:"]]
 [[=JAM_VERSION=] [A predefined global variable with two elements indicates the version number of Boost Jam. Boost Jam versions start at "=03=" "=00=". Earlier versions of =Jam= do not automatically define =JAM_VERSION=.]]
 ]
 
@@ -1302,7 +1302,7 @@
 
 [section JAMSHELL]
 
-When =bjam= executes a rule's action block, it forks and execs a shell, passing the action block as an argument to the shell. The invocation of the shell can be controlled by =$(JAMSHELL)=. The default on Unix is, for example:
+When =b2= executes a rule's action block, it forks and execs a shell, passing the action block as an argument to the shell. The invocation of the shell can be controlled by =$(JAMSHELL)=. The default on Unix is, for example:
 
 [pre
 JAMSHELL = /bin/sh -c % ;
@@ -1310,9 +1310,9 @@
 
 The =%= is replaced with the text of the action block.
 
-=BJam= does not directly support building in parallel across multiple hosts, since that is heavily dependent on the local environment. To build in parallel across multiple hosts, you need to write your own shell that provides access to the multiple hosts. You then reset =$(JAMSHELL)= to reference it.
+=B2= does not directly support building in parallel across multiple hosts, since that is heavily dependent on the local environment. To build in parallel across multiple hosts, you need to write your own shell that provides access to the multiple hosts. You then reset =$(JAMSHELL)= to reference it.
 
-Just as =bjam= expands a =%= to be the text of the rule's action block, it expands a =!= to be the multi-process slot number. The slot number varies between 1 and the number of concurrent jobs permitted by the =-j= flag given on the command line. Armed with this, it is possible to write a multiple host shell. For example:
+Just as =b2= expands a =%= to be the text of the rule's action block, it expands a =!= to be the multi-process slot number. The slot number varies between 1 and the number of concurrent jobs permitted by the =-j= flag given on the command line. Armed with this, it is possible to write a multiple host shell. For example:
 
 [pre
 #!/bin/sh
@@ -1340,7 +1340,7 @@
 [section:actionrule =__TIMING_RULE__= and =__ACTION_RULE__=]
 
 The =__TIMING_RULE__= and =__ACTION_RULE__= can be set to the name of a rule
-for =bjam= to call *after* an action completes for a target. They both give
+for =b2= to call *after* an action completes for a target. They both give
 diagnostic information about the action that completed. For =__TIMING_RULE__=
 the rule is called as:
 
@@ -1357,7 +1357,7 @@
         [Any values following the rule name in the =__TIMING_RULE__= or =__ACTION_RULE__=
         are passed along here.]]
     [[[^target]]
- [The =bjam= target that was built.]]
+ [The =b2= target that was built.]]
     [[[^command]]
         [The text of the executed command in the action body.]]
     [[[^status]]
@@ -1586,7 +1586,7 @@
 
 [section Diagnostics]
 
-In addition to generic error messages, =bjam= may emit one of the following:
+In addition to generic error messages, =b2= may emit one of the following:
 
 [pre warning: unknown rule X]
 
@@ -1626,7 +1626,7 @@
 
 [pre X removed]
 
-=BJam= removed a partially built target after being interrupted.
+=B2= removed a partially built target after being interrupted.
 
 [endsect]
 
@@ -1634,7 +1634,7 @@
 
 For parallel building to be successful, the dependencies among files must be properly spelled out, as targets tend to get built in a quickest-first ordering. Also, beware of un-parallelizable commands that drop fixed-named files into the current directory, like =yacc(1)= does.
 
-A poorly set =$(JAMSHELL)= is likely to result in silent failure.
+A poorly set =$(JAMSHELL)= is likely to result in silent failure.
 
 [endsect]
 
@@ -1674,7 +1674,7 @@
 * A variable whose value is an empty list or which consists entirely of empty
  strings has a negative logical value. Thus, for example, code like the
  following allows a sensible non-empty default which can easily be overridden
- by the user:
+ by the user:
  ``
 MESSAGE ?\= starting jam... ;
 if $(MESSAGE) { ECHO The message is: $(MESSAGE) ; }

Modified: branches/release/tools/build/v2/doc/jamfile.jam
==============================================================================
--- branches/release/tools/build/v2/doc/jamfile.jam (original)
+++ branches/release/tools/build/v2/doc/jamfile.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,8 +2,8 @@
 # Distributed under the Boost Software License, Version 1.0.
 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
-import quickbook
- ;
+import quickbook ;
+using boostbook ;
 
 project tools/build/v2/doc
     ;

Modified: branches/release/tools/build/v2/doc/src/architecture.xml
==============================================================================
--- branches/release/tools/build/v2/doc/src/architecture.xml (original)
+++ branches/release/tools/build/v2/doc/src/architecture.xml 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,399 +6,425 @@
     <title>Boost.Build v2 architecture</title>
 
   <sidebar>
- <para>This document is work-in progress. Don't expect much from it
- yet.</para>
+ <para>
+ This document is work-in progress. Do not expect much from it yet.
+ </para>
   </sidebar>
-
+
   <section id="bbv2.arch.overview">
     <title>Overview</title>
 
- <para>The Boost.Build code is structured in four different components:
+ <para>
+ Boost.Build implementation is structured in four different components:
     "kernel", "util", "build" and "tools". The first two are relatively
- uninteresting, so we'll focus on the remaining pair. The "build" component
- provides classes necessary to declare targets, determine which properties
- should be used for their building, and for creating the dependency
- graph. The "tools" component provides user-visible functionality. It
- mostly allows to declare specific kind of main targets, and declare
- avaiable tools, which are then used when creating the dependency graph.
+ uninteresting, so we will focus on the remaining pair. The "build" component
+ provides classes necessary to declare targets, determining which properties
+ should be used for their building, and creating the dependency graph. The
+ "tools" component provides user-visible functionality. It mostly allows
+ declaring specific kinds of main targets, as well as registering available
+ tools, which are then used when creating the dependency graph.
     </para>
-
   </section>
 
   <section id="bbv2.arch.build">
     <title>The build layer</title>
 
- <para>The build layer has just four main parts -- metatargets (abstract targets),
- virtual targets, generators and properties.
- <itemizedlist>
- <listitem><para>Metatargets (see the "targets.jam" module) represent
- all the user-defined entities which can be built. The "meta" prefix
- signify that they don't really corrspond to files -- depending of
- build request, they can produce different set of
- files. Metatargets are created when Jamfiles are loaded. Each
- metagarget has a <code>generate</code> method which is given a
- property set and produces virtual targets for the passed properties.
- </para></listitem>
- <listitem><para>Virtual targets (see the "virtual-targets.jam"
- module) correspond to the atomic things which can be updated --
- most typically files.
- </para></listitem>
- <listitem><para>Properties are just (name, value) pairs, specified
- by the user and describing how the targets should be
- built. Properties are stored using the <code>property-set</code> class.
- </para></listitem>
- <listitem><para>Generators are the objects which encapsulate tools
- -- they can take a list of source virtual targets and produce new
- virtual targets from them.
- </para></listitem>
- </itemizedlist>
+ <para>
+ The build layer has just four main parts -- metatargets (abstract
+ targets), virtual targets, generators and properties.
+
+ <itemizedlist>
+ <listitem><para>
+ Metatargets (see the "targets.jam" module) represent all the
+ user-defined entities that can be built. The "meta" prefix signifies
+ that they do not need to correspond to exact files or even files at all
+ -- they can produce a different set of files depending on the build
+ request. Metatargets are created when Jamfiles are loaded. Each has a
+ <code>generate</code> method which is given a property set and produces
+ virtual targets for the passed properties.
+ </para></listitem>
+ <listitem><para>
+ Virtual targets (see the "virtual-targets.jam" module) correspond to
+ actual atomic updatable entities -- most typically files.
+ </para></listitem>
+ <listitem><para>
+ Properties are just (name, value) pairs, specified by the user and
+ describing how targets should be built. Properties are stored using the
+ <code>property-set</code> class.
+ </para></listitem>
+ <listitem><para>
+ Generators are objects that encapsulate specific tools -- they can
+ take a list of source virtual targets and produce new virtual targets
+ from them.
+ </para></listitem>
+ </itemizedlist>
+ </para>
+
+ <para>
+ The build process includes the following steps:
+
+ <orderedlist>
+ <listitem><para>
+ Top-level code calls the <code>generate</code> method of a metatarget
+ with some properties.
+ </para></listitem>
+
+ <listitem><para>
+ The metatarget combines the requested properties with its requirements
+ and passes the result, together with the list of sources, to the
+ <code>generators.construct</code> function.
+ </para></listitem>
+
+ <listitem><para>
+ A generator appropriate for the build properties is selected and its
+ <code>run</code> method is called. The method returns a list of virtual
+ targets
+ </para></listitem>
+
+ <listitem><para>
+ The targets are returned to the top level code. They are converted
+ into bjam targets (via <code>virtual-target.actualize</code>) and passed
+ to bjam for building.
+ </para></listitem>
+ </orderedlist>
+ </para>
+
+ <section id="bbv2.arch.build.metatargets">
+ <title>Metatargets</title>
+
+ <para>
+ There are several classes derived from "abstract-target". The
+ "main-target" class represents a top-level main target, the
+ "project-target" class acts like a container holding multiple main
+ targets, and "basic-target" class is a base class for all further target
+ types.
       </para>
 
- <para>The build process includes those steps:
- <orderedlist>
- <listitem><para>Top-level code calls the <code>generate</code>
- method of a metatarget with some properties. </para></listitem>
-
-
- <listitem><para>The metatarget combines the requested properties
- with requirements and passes the result, together with the list
- of sources, to the <code>generators.construct</code>
- function</para></listitem>
-
-
- <listitem><para>A generator appropriate for the build properties is
- selected and its <code>run</code> method is
- called. The method returns a list of virtual targets
- </para></listitem>
-
- <listitem><para>The targets are returned to the top level code. They
- are converted into bjam targets (via
- <code>virtual-target.actualize</code>) and passed to bjam for building.
- </para></listitem>
- </orderedlist>
- </para>
-
- <section id="bbv2.arch.metatargets">
- <title>Metatargets</title>
-
- <para>There are several classes derived from "abstract-target". The
- "main-target" class represents top-level main target, the "project-target"
- acts like container for all main targets, and "basic-target" class is a
- base class for all further target types.
- </para>
-
- <para>Since each main target can have several alternatives, all top-level
- target objects are just containers, referring to "real" main target
- classes. The type is that container is "main-target". For example, given:
+ <para>
+ Since each main target can have several alternatives, all top-level
+ target objects are actually containers, referring to "real" main target
+ classes. The type of that container is "main-target". For example, given:
 <programlisting>
 alias a ;
 lib a : a.cpp : &lt;toolset&gt;gcc ;
 </programlisting>
- we would have one-top level instance of "main-target-class", which will
- contain one instance of "alias-target-class" and one instance of
- "lib-target-class". The "generate" method of "main-target" decides
- which of the alternative should be used, and call "generate" on the
- corresponding instance.
- </para>
-
- <para>Each alternative is a instance of a class derived from
- "basic-target". The "basic-target.generate" does several things that are
- always should be done:
- <itemizedlist>
- <listitem>
- <para>Determines what properties should be used for building the
- target. This includes looking at requested properties, requirements,
- and usage requirements of all sources.</para>
- </listitem>
- <listitem>
- <para>Builds all sources</para>
- </listitem>
- <listitem>
- <para>Computes the usage requirements which should be passes back.</para>
- </listitem>
- </itemizedlist>
- For the real work of constructing virtual target, a new method
- "construct" is called.
- </para>
-
- <para>The "construct" method can be implemented in any way by classes
- derived from "basic-target", but one specific derived class plays the
- central role -- "typed-target". That class holds the desired type of file
- to be produces, and calls the generators modules to do the job.
- </para>
-
- <para>This means that a specific metatarget subclass may avoid using
- generators at all. However, this is deprecated and we're trying to
- eliminate all such subsclasses at the moment.
- </para>
-
- <para>Note that the <filename>build/targets.jam</filename> file contains
- an UML diagram which might help.</para>
-
- </section>
-
- <section id="bbv2.arch.virtual">
- <title>Virtual targets</title>
-
- <para>Virtual targets correspond to the atomic things which can be
- updated. Each virtual target can be assigned an updating action --
- instance of the <code>action</code> class. The action class, in
- turn, contains a list of source targets, properties, and a name of
- bjam action block which should be executed.
- </para>
-
- <para>We try hard to never create equal instances of the
- <code>virtual-target</code> class. Each code which creates virtual
- targets passes them though the <code>virtual-target.register</code>
- function, which detects if a target with the same name, sources, and
- properties was created. In that case, existing target is returned.
- </para>
-
- <para>When all virtual targets are produced, they are
- "actualized". This means that the real file names are computed, and
- the commands that should be run are generated. This is done by the
- <code>virtual-target.actualize</code> method and the
- <code>action.actualize</code> methods. The first is conceptually
- simple, while the second need additional explanation. The commands
- in bjam are generated in two-stage process. First, a rule with the
- appropriate name (for example
- "gcc.compile") is called and is given the names of targets. The rule
- sets some variables, like "OPTIONS". After that, the command string
- is taken, and variable are substitutes, so use of OPTIONS inside the
- command string become the real compile options.
- </para>
-
- <para>Boost.Build added a third stage to simplify things. It's now
- possible to automatically convert properties to appropriate assignments to
- variables. For example, &lt;debug-symbols&gt;on would add "-g" to the
- OPTIONS variable, without requiring to manually add this logic to
- gcc.compile. This functionality is part of the "toolset" module.
- </para>
-
- <para>Note that the <filename>build/virtual-targets.jam</filename> file
- contains an UML diagram which might help.</para>
- </section>
-
- <section id="bbv2.arch.properties">
- <para>Above, we noted that metatargets are built with a set of
- properties. That set is represented with the
- <code>property-set</code> class. An important point is that handling
- of property sets can get very expensive. For that reason, we make
- sure that for each set of (name, value) pairs only one
- <code>property-set</code> instance is created. The
- <code>property-set</code> uses extensive caching for all operation,
- so most work is avoided. The <code>property-set.create</code> is the
- factory function which should be used to create instances of the
- <code>property-set</code> class.
- </para>
- </section>
-
-
+ we would have one-top level "main-target" instance, containing one
+ "alias-target" and one "lib-target" instance. "main-target"'s "generate"
+ method decides which of the alternative should be used, and calls
+ "generate" on the corresponding instance.
+ </para>
+
+ <para>
+ Each alternative is an instance of a class derived from "basic-target".
+ "basic-target.generate" does several things that should always be done:
+
+ <itemizedlist>
+ <listitem><para>
+ Determines what properties should be used for building the target.
+ This includes looking at requested properties, requirements, and usage
+ requirements of all sources.
+ </para></listitem>
+
+ <listitem><para>
+ Builds all sources.
+ </para></listitem>
+
+ <listitem><para>
+ Computes usage requirements that should be passed back to targets
+ depending on this one.
+ </para></listitem>
+ </itemizedlist>
+
+ For the real work of constructing a virtual target, a new method
+ "construct" is called.
+ </para>
+
+ <para>
+ The "construct" method can be implemented in any way by classes derived
+ from "basic-target", but one specific derived class plays the central role
+ -- "typed-target". That class holds the desired type of file to be
+ produced, and its "construct" method uses the generators module to do the
+ actual work.
+ </para>
+
+ <para>
+ This means that a specific metatarget subclass may avoid using
+ generators all together. However, this is deprecated and we are trying to
+ eliminate all such subclasses at the moment.
+ </para>
+
+ <para>
+ Note that the <filename>build/targets.jam</filename> file contains an
+ UML diagram which might help.
+ </para>
+ </section>
+
+ <section id="bbv2.arch.build.virtual">
+ <title>Virtual targets</title>
+
+ <para>
+ Virtual targets correspond to atomic updatable entities. Each virtual
+ target can be assigned an updating action -- instance of the
+ <code>action</code> class. The action class, in turn, contains a list of
+ source targets, properties, and a name of an bjam action which should be
+ executed.
+ </para>
+
+ <para>
+ We try hard to never create equal instances of the
+ <code>virtual-target</code> class. Code creating virtual targets passes
+ them though the <code>virtual-target.register</code> function, which
+ detects if a target with the same name, sources, and properties has
+ already been created. In that case, the preexisting target is returned.
+ </para>
+
+ <para>
+ When all virtual targets are produced, they are "actualized". This means
+ that the real file names are computed, and the commands that should be run
+ are generated. This is done by the <code>virtual-target.actualize</code>
+ and <code>action.actualize</code> methods. The first is conceptually
+ simple, while the second needs additional explanation. Commands in bjam
+ are generated in a two-stage process. First, a rule with an appropriate
+ name (for example "gcc.compile") is called and is given a list of target
+ names. The rule sets some variables, like "OPTIONS". After that, the
+ command string is taken, and variable are substitutes, so use of OPTIONS
+ inside the command string gets transformed into actual compile options.
+ </para>
+
+ <para>
+ Boost.Build added a third stage to simplify things. It is now possible
+ to automatically convert properties to appropriate variable assignments.
+ For example, &lt;debug-symbols&gt;on would add "-g" to the OPTIONS
+ variable, without requiring to manually add this logic to gcc.compile.
+ This functionality is part of the "toolset" module.
+ </para>
+
+ <para>
+ Note that the <filename>build/virtual-targets.jam</filename> file
+ contains an UML diagram which might help.
+ </para>
+ </section>
+
+ <section id="bbv2.arch.build.properties">
+ <title>Properties</title>
+
+ <para>
+ Above, we noted that metatargets are built with a set of properties.
+ That set is represented by the <code>property-set</code> class. An
+ important point is that handling of property sets can get very expensive.
+ For that reason, we make sure that for each set of (name, value) pairs
+ only one <code>property-set</code> instance is created. The
+ <code>property-set</code> uses extensive caching for all operations, so
+ most work is avoided. The <code>property-set.create</code> is the factory
+ function used to create instances of the <code>property-set</code> class.
+ </para>
+ </section>
   </section>
 
   <section id="bbv2.arch.tools">
     <title>The tools layer</title>
 
     <para>Write me!</para>
+ </section>
+
+ <section id="bbv2.arch.targets">
+ <title>Targets</title>
 
+ <para>NOTE: THIS SECTION IS NOT EXPECTED TO BE READ!
+ There are two user-visible kinds of targets in Boost.Build. First are
+ "abstract" &#x2014; they correspond to things declared by the user, e.g.
+ projects and executable files. The primary thing about abstract targets is
+ that it is possible to request them to be built with a particular set of
+ properties. Each property combination may possibly yield different built
+ files, so abstract target do not have a direct correspondence to built
+ files.
+ </para>
+
+ <para>
+ File targets, on the other hand, are associated with concrete files.
+ Dependency graphs for abstract targets with specific properties are
+ constructed from file targets. User has no way to create file targets but
+ can specify rules for detecting source file types, as well as rules for
+ transforming between file targets of different types. That information is
+ used in constructing the final dependency graph, as described in the <link
+ linkend="bbv2.arch.depends">next section</link>.
+ <emphasis role="bold">Note:</emphasis>File targets are not the same entities
+ as Jam targets; the latter are created from file targets at the latest
+ possible moment.
+ <emphasis role="bold">Note:</emphasis>"File target" is an originally
+ proposed name for what we now call virtual targets. It is more
+ understandable by users, but has one problem: virtual targets can
+ potentially be "phony", and not correspond to any file.
+ </para>
   </section>
-
- <section id="bbv2.arch.targets">
- <title>Targets</title>
-
- <para>NOTE: THIS SECTION IS NOT EXPECTED TO BE READ!
- There are two user-visible kinds of targets in Boost.Build.
- First are "abstract" &#x2014; they correspond to things declared
- by user, for example, projects and executable files. The primary
- thing about abstract target is that it's possible to request them
- to be build with a particular values of some properties. Each
- combination of properties may possible yield different set of
- real file, so abstract target do not have a direct correspondence
- with files.</para>
-
- <para>File targets, on the contary, are associated with concrete
- files. Dependency graphs for abstract targets with specific
- properties are constructed from file targets. User has no was to
- create file targets, however it can specify rules that detect
- file type for sources, and also rules for transforming between
- file targets of different types. That information is used in
- constructing dependency graph, as desribed in the "next section".
- [ link? ] <emphasis role="bold">Note:</emphasis>File targets are not
- the same as targets in Jam sense; the latter are created from
- file targets at the latest possible moment. <emphasis role="bold">Note:</emphasis>"File
- target" is a proposed name for what we call virtual targets. It
- it more understandable by users, but has one problem: virtual
- targets can potentially be "phony", and not correspond to any
- file.</para>
-
- <section id="bbv2.arch.depends">
- <title>Dependency scanning</title>
-
- <para>Dependency scanning is the process of finding implicit
- dependencies, like "#include" statements in C++. The requirements
- for right dependency scanning mechanism are:</para>
-
- <itemizedlist>
- <listitem>
- <simpara>
- Support for different scanning algorithms. C++ and XML have
- quite different syntax for includes and rules for looking up
- included files.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- Ability to scan the same file several times. For example,
- single C++ file can be compiled with different include
- paths.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- Proper detection of dependencies on generated files.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- Proper detection of dependencies from generated file.
- </simpara>
- </listitem>
- </itemizedlist>
-
- <section>
- <title>Support for different scanning algorithms</title>
-
- <para>Different scanning algorithm are encapsulated by objects
- called "scanners". Please see the documentation for "scanner"
- module for more details.</para>
-
- </section>
-
- <section>
- <title>Ability to scan the same file several times</title>
-
- <para>As said above, it's possible to compile a C++ file twice, with
- different include paths. Therefore, include dependencies for
- those compilations can be different. The problem is that bjam
- does not allow several scans of the same target.</para>
-
- <para>The solution in Boost.Build is straigtforward. When a virtual
- target is converted to bjam target (via
- <literal>virtual-target.actualize</literal> method), we specify the scanner
- object to be used. The actualize method will create different
- bjam targets for different scanners.</para>
-
- <para>All targets with specific scanner are made dependent on target
- without scanner, which target is always created. This is done in
- case the target is updated. The updating action will be
- associated with target without scanner, but if sources for that
- action are touched, all targets &#x2014; with scanner and without
- should be considered outdated.</para>
-
- <para>For example, assume that "a.cpp" is compiled by two compilers
- with different include path. It's also copied into some install
- location. In turn, it's produced from "a.verbatim". The
- dependency graph will look like:</para>
+
+ <section id="bbv2.arch.depends">
+ <title>Dependency scanning</title>
+
+ <para>
+ Dependency scanning is the process of finding implicit dependencies, like
+ "#include" statements in C++. The requirements for correct dependency
+ scanning mechanism are:
+ </para>
+
+ <itemizedlist>
+ <listitem><simpara>
+ <link linkend="bbv2.arch.depends.different-scanning-algorithms">Support
+ for different scanning algorithms</link>. C++ and XML have quite different
+ syntax for includes and rules for looking up the included files.
+ </simpara></listitem>
+
+ <listitem><simpara>
+ <link linkend="bbv2.arch.depends.same-file-different-scanners">Ability
+ to scan the same file several times</link>. For example, a single C++ file
+ may be compiled using different include paths.
+ </simpara></listitem>
+
+ <listitem><simpara>
+ <link linkend="bbv2.arch.depends.dependencies-on-generated-files">Proper
+ detection of dependencies on generated files.</link>
+ </simpara></listitem>
+
+ <listitem><simpara>
+ <link
+ linkend="bbv2.arch.depends.dependencies-from-generatedfiles">Proper
+ detection of dependencies from a generated file.</link>
+ </simpara></listitem>
+ </itemizedlist>
+
+ <section id="bbv2.arch.depends.different-scanning-algorithms">
+ <title>Support for different scanning algorithms</title>
+
+ <para>
+ Different scanning algorithm are encapsulated by objects called
+ "scanners". Please see the "scanner" module documentation for more
+ details.
+ </para>
+ </section>
+
+ <section id="bbv2.arch.depends.same-file-different-scanners">
+ <title>Ability to scan the same file several times</title>
+
+ <para>
+ As stated above, it is possible to compile a C++ file multiple times,
+ using different include paths. Therefore, include dependencies for those
+ compilations can be different. The problem is that bjam does not allow
+ multiple scans of the same target.
+ </para>
+
+ <para>
+ The solution in Boost.Build is straightforward. When a virtual target is
+ converted to a bjam target (via the
+ <literal>virtual-target.actualize</literal> method), we specify the
+ scanner object to be used. The actualize method will create different bjam
+ targets for different scanners.
+ </para>
+
+ <para>
+ For each Boost Jam target created with a scanner is created, a
+ corresponding one is created without it. The updating action is
+ associated with the scanner-less target, and the target with the scanner
+ is made to depend on it. That way if sources for that action are touched,
+ all targets &#x2014; with and without the scanner are considered outdated.
+ </para>
+
+ <para>
+ Consider the following example: "a.cpp" prepared from "a.verbatim",
+ compiled by two compilers using different include paths and copied into
+ some install location. The dependency graph would look like:
+ </para>
 
 <programlisting>
-a.o (&lt;toolset&gt;gcc) &lt;--(compile)-- a.cpp (scanner1) ----+
-a.o (&lt;toolset&gt;msvc) &lt;--(compile)-- a.cpp (scanner2) ----|
+a.o (&lt;toolset&gt;gcc) &lt;--(compile)-- a.cpp (scanner1) ----+
+a.o (&lt;toolset&gt;msvc) &lt;--(compile)-- a.cpp (scanner2) ----|
 a.cpp (installed copy) &lt;--(copy) ----------------------- a.cpp (no scanner)
                                                                  ^
                                                                  |
                        a.verbose --------------------------------+
 </programlisting>
+ </section>
+
+ <section id="bbv2.arch.depends.dependencies-on-generated-files">
+ <title>Proper detection of dependencies on generated files.</title>
+
+ <para>
+ This requirement breaks down to the following ones.
+ </para>
+
+ <orderedlist>
+ <listitem><simpara>
+ If when compiling "a.cpp" there is an include of "a.h", the "dir"
+ directory is on the include path, and a target called "a.h" will be
+ generated in "dir", then bjam should discover the include, and create
+ "a.h" before compiling "a.cpp".
+ </simpara></listitem>
+
+ <listitem><simpara>
+ Since Boost.Build almost always generates targets under the "bin"
+ directory, this should be supported as well. I.e. in the scenario above,
+ Jamfile in "dir" might create a main target, which generates "a.h". The
+ file will be generated to "dir/bin" directory, but we still have to
+ recognize the dependency.
+ </simpara></listitem>
+ </orderedlist>
+
+ <para>
+ The first requirement means that when determining what "a.h" means when
+ found in "a.cpp", we have to iterate over all directories in include
+ paths, checking for each one:
+ </para>
+
+ <orderedlist>
+ <listitem><simpara>
+ If there is a file named "a.h" in that directory, or
+ </simpara></listitem>
+
+ <listitem><simpara>
+ If there is a target called "a.h", which will be generated in that
+ that directory.
+ </simpara></listitem>
+ </orderedlist>
+
+ <para>
+ Classic Jam has built-in facilities for point (1) above, but that is not
+ enough. It is hard to implement the right semantics without builtin
+ support. For example, we could try to check if there exists a target
+ called "a.h" somewhere in the dependency graph, and add a dependency to
+ it. The problem is that without a file search in the include path, the
+ semantics may be incorrect. For example, one can have an action that
+ generated some "dummy" header, for systems which do not have a native one.
+ Naturally, we do not want to depend on that generated header on platforms
+ where a native one is included.
+ </para>
 
- </section>
- <section>
- <title>Proper detection of dependencies on generated files.</title>
-
- <para>This requirement breaks down to the following ones.</para>
-
- <orderedlist>
- <listitem>
- <simpara>
- If when compiling "a.cpp" there's include of "a.h", the
- "dir" directory is in include path, and a target called "a.h"
- will be generated to "dir", then bjam should discover the
- include, and create "a.h" before compiling "a.cpp".
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- Since almost always Boost.Build generates targets to a
- "bin" directory, it should be supported as well. I.e. in the
- scanario above, Jamfile in "dir" might create a main target,
- which generates "a.h". The file will be generated to "dir/bin"
- directory, but we still have to recognize the dependency.
- </simpara>
- </listitem>
- </orderedlist>
-
- <para>The first requirement means that when determining what "a.h"
- means, when found in "a.cpp", we have to iterate over all
- directories in include paths, checking for each one:</para>
-
- <orderedlist>
- <listitem>
- <simpara>
- If there's file "a.h" in that directory, or
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- If there's a target called "a.h", which will be generated
- to that directory.
- </simpara>
- </listitem>
- </orderedlist>
-
- <para>Classic Jam has built-in facilities for point (1) above, but
- that's not enough. It's hard to implement the right semantic
- without builtin support. For example, we could try to check if
- there's targer called "a.h" somewhere in dependency graph, and
- add a dependency to it. The problem is that without search in
- include path, the semantic may be incorrect. For example, one can
- have an action which generated some "dummy" header, for system
- which don't have the native one. Naturally, we don't want to
- depend on that generated header on platforms where native one is
- included.</para>
-
- <para>There are two design choices for builtin support. Suppose we
- have files a.cpp and b.cpp, and each one includes header.h,
- generated by some action. Dependency graph created by classic jam
- would look like:</para>
+ <para>
+ There are two design choices for builtin support. Suppose we have files
+ a.cpp and b.cpp, and each one includes header.h, generated by some action.
+ Dependency graph created by classic Jam would look like:
 
 <programlisting>
 a.cpp -----&gt; &lt;scanner1&gt;header.h [search path: d1, d2, d3]
 
-
                   &lt;d2&gt;header.h --------&gt; header.y
                   [generated in d2]
-
-b.cpp -----&gt; &lt;scanner2&gt;header.h [ search path: d1, d2, d4]
+
+b.cpp -----&gt; &lt;scanner2&gt;header.h [search path: d1, d2, d4]
 </programlisting>
+ </para>
 
- <para>
-In this case, Jam thinks all header.h target are not
-realated. The right dependency graph might be:
+ <para>
+ In this case, Jam thinks all header.h target are not related. The
+ correct dependency graph might be:
 
 <programlisting>
-a.cpp ----
+a.cpp ----
           \
- \
- &gt;----&gt; &lt;d2&gt;header.h --------&gt; header.y
- / [generated in d2]
- /
+ &gt;----&gt; &lt;d2&gt;header.h --------&gt; header.y
+ / [generated in d2]
 b.cpp ----
 </programlisting>
 
-or
+ or
 
 <programlisting>
 a.cpp -----&gt; &lt;scanner1&gt;header.h [search path: d1, d2, d3]
@@ -408,120 +434,126 @@
                   &lt;d2&gt;header.h --------&gt; header.y
                   [generated in d2]
                           ^
- (includes)
+ (includes)
                           |
 b.cpp -----&gt; &lt;scanner2&gt;header.h [ search path: d1, d2, d4]
 </programlisting>
- </para>
+ </para>
+
+ <para>
+ The first alternative was used for some time. The problem however is:
+ what include paths should be used when scanning header.h? The second
+ alternative was suggested by Matt Armstrong. It has a similar effect: Any
+ target depending on &lt;scanner1&gt;header.h will also depend on
+ &lt;d2&gt;header.h. This way though we now have two different targets with
+ two different scanners, so those targets can be scanned independently. The
+ first alternative's problem is avoided, so the second alternative is
+ implemented now.
+ </para>
+
+ <para>
+ The second sub-requirements is that targets generated under the "bin"
+ directory are handled as well. Boost.Build implements a semi-automatic
+ approach. When compiling C++ files the process is:
+ </para>
+
+ <orderedlist>
+ <listitem><simpara>
+ The main target to which the compiled file belongs to is found.
+ </simpara></listitem>
+
+ <listitem><simpara>
+ All other main targets that the found one depends on are found. These
+ include: main targets used as sources as well as those specified as
+ "dependency" properties.
+ </simpara></listitem>
+
+ <listitem><simpara>
+ All directories where files belonging to those main targets will be
+ generated are added to the include path.
+ </simpara></listitem>
+ </orderedlist>
+
+ <para>
+ After this is done, dependencies are found by the approach explained
+ previously.
+ </para>
+
+ <para>
+ Note that if a target uses generated headers from another main target,
+ that main target should be explicitly specified using the dependency
+ property. It would be better to lift this requirement, but it does not
+ seem to be causing any problems in practice.
+ </para>
+
+ <para>
+ For target types other than C++, adding of include paths must be
+ implemented anew.
+ </para>
+ </section>
+
+ <section id="bbv2.arch.depends.dependencies-from-generated-files">
+ <title>Proper detection of dependencies from generated files</title>
 
- <para>
-The first alternative was used for some time. The problem
-however is: what include paths should be used when scanning
-header.h? The second alternative was suggested by Matt Armstrong.
-It has similiar effect: add targets which depend on
-&lt;scanner1&gt;header.h will also depend on &lt;d2&gt;header.h.
-But now we have two different target with two different scanners,
-and those targets can be scanned independently. The problem of
-first alternative is avoided, so the second alternative is
-implemented now.
- </para>
-
- <para>The second sub-requirements is that targets generated to "bin"
- directory are handled as well. Boost.Build implements
- semi-automatic approach. When compiling C++ files the process
- is:</para>
-
- <orderedlist>
- <listitem>
- <simpara>
- The main target to which compiled file belongs is found.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- All other main targets that the found one depends on are
- found. Those include main target which are used as sources, or
- present as values of "dependency" features.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- All directories where files belonging to those main target
- will be generated are added to the include path.
- </simpara>
- </listitem>
- </orderedlist>
-
- <para>After this is done, dependencies are found by the approach
- explained previously.</para>
-
- <para>Note that if a target uses generated headers from other main
- target, that main target should be explicitly specified as
- dependency property. It would be better to lift this requirement,
- but it seems not very problematic in practice.</para>
-
- <para>For target types other than C++, adding of include paths must
- be implemented anew.</para>
-
- </section>
- <section>
- <title>Proper detection of dependencies from generated files</title>
-
- <para>Suppose file "a.cpp" includes "a.h" and both are generated by
- some action. Note that classic jam has two stages. In first stage
- dependency graph graph is build and actions which should be run
- are determined. In second stage the actions are executed.
- Initially, neither file exists, so the include is not found. As
- the result, jam might attempt to compile a.cpp before creating
- a.h, and compilation will fail.</para>
-
- <para>The solution in Boost.Jam is to perform additional dependency
- scans after targets are updated. This break separation between
- build stages in jam &#x2014; which some people consider a good
- thing &#x2014; but I'm not aware of any better solution.</para>
-
- <para>In order to understand the rest of this section, you better
- read some details about jam dependency scanning, available
- <ulink url=
- "http://public.perforce.com:8080/@md=d&amp;cd=//public/jam/src/&amp;ra=s&amp;c=kVu@//2614?ac=10">
- at this link</ulink>.</para>
-
- <para>Whenever a target is updated, Boost.Jam rescans it for
- includes. Consider this graph, created before any actions are
- run.</para>
+ <para>
+ Suppose file "a.cpp" includes "a.h" and both are generated by some
+ action. Note that classic Jam has two stages. In the first stage the
+ dependency graph is built and actions to be run are determined. In the
+ second stage the actions are executed. Initially, neither file exists, so
+ the include is not found. As the result, Jam might attempt to compile
+ a.cpp before creating a.h, causing the compilation to fail.
+ </para>
+
+ <para>
+ The solution in Boost.Jam is to perform additional dependency scans
+ after targets are updated. This breaks separation between build stages in
+ Jam &#x2014; which some people consider a good thing &#x2014; but I am not
+ aware of any better solution.
+ </para>
+
+ <para>
+ In order to understand the rest of this section, you better read some
+ details about Jam's dependency scanning, available at <ulink url=
+ "http://public.perforce.com:8080/@md=d&amp;cd=//public/jam/src/&amp;ra=s&amp;c=kVu@//2614?ac=10">
+ this link</ulink>.
+ </para>
 
+ <para>
+ Whenever a target is updated, Boost.Jam rescans it for includes.
+ Consider this graph, created before any actions are run.
 <programlisting>
 A -------&gt; C ----&gt; C.pro
      /
 B --/ C-includes ---&gt; D
 </programlisting>
+ </para>
+
+ <para>
+ Both A and B have dependency on C and C-includes (the latter dependency
+ is not shown). Say during building we have tried to create A, then tried
+ to create C and successfully created C.
+ </para>
 
- <para>
-Both A and B have dependency on C and C-includes (the latter
-dependency is not shown). Say during building we've tried to create
-A, then tried to create C and successfully created C.
- </para>
-
- <para>In that case, the set of includes in C might well have
- changed. We do not bother to detect precisely which includes were
- added or removed. Instead we create another internal node
- C-includes-2. Then we determine what actions should be run to
- update the target. In fact this mean that we perform logic of
- first stage while already executing stage.</para>
-
- <para>After actions for C-includes-2 are determined, we add
- C-includes-2 to the list of A's dependents, and stage 2 proceeds
- as usual. Unfortunately, we can't do the same with target B,
- since when it's not visited, C target does not know B depends on
- it. So, we add a flag to C which tells and it was rescanned. When
- visiting B target, the flag is notices and C-includes-2 will be
- added to the list of B's dependencies.</para>
+ <para>
+ In that case, the set of includes in C might well have changed. We do
+ not bother to detect precisely which includes were added or removed.
+ Instead we create another internal node C-includes-2. Then we determine
+ what actions should be run to update the target. In fact this means that
+ we perform the first stage logic when already in the execution stage.
+ </para>
 
- <para>Note also that internal nodes are sometimes updated too.
- Consider this dependency graph:</para>
+ <para>
+ After actions for C-includes-2 are determined, we add C-includes-2 to
+ the list of A's dependents, and stage 2 proceeds as usual. Unfortunately,
+ we can not do the same with target B, since when it is not visited, C
+ target does not know B depends on it. So, we add a flag to C marking it as
+ rescanned. When visiting the B target, the flag is noticed and
+ C-includes-2 is added to the list of B's dependencies as well.
+ </para>
 
+ <para>
+ Note also that internal nodes are sometimes updated too. Consider this
+ dependency graph:
 <programlisting>
 a.o ---&gt; a.cpp
             a.cpp-includes --&gt; a.h (scanned)
@@ -530,106 +562,106 @@
                                                                  |
             a.pro &lt;-------------------------------------------+
 </programlisting>
+ </para>
+
+ <para>
+ Here, our handling of generated headers come into play. Say that a.h
+ exists but is out of date with respect to "a.pro", then "a.h (generated)"
+ and "a.h-includes" will be marked for updating, but "a.h (scanned)" will
+ not. We have to rescan "a.h" after it has been created, but since "a.h
+ (generated)" has no associated scanner, it is only possible to rescan
+ "a.h" after "a.h-includes" target has been updated.
+ </para>
 
- <para>Here, out handling of generated headers come into play. Say
- that a.h exists but is out of date with respect to "a.pro", then
- "a.h (generated)" and "a.h-includes" will be marking for
- updating, but "a.h (scanned)" won't be marked. We have to rescan
- "a.h" file after it's created, but since "a.h (generated)" has no
- scanner associated with it, it's only possible to rescan "a.h"
- after "a.h-includes" target was updated.</para>
-
- <para>Tbe above consideration lead to decision that we'll rescan a
- target whenever it's updated, no matter if this target is
- internal or not.</para>
+ <para>
+ The above consideration lead to the decision to rescan a target whenever
+ it is updated, no matter if it is internal or not.
+ </para>
+
+ </section>
+ </section>
 
   <warning>
     <para>
- The remainder of this document is not indended to be read at
- all. This will be rearranged in future.
+ The remainder of this document is not intended to be read at all. This
+ will be rearranged in the future.
     </para>
   </warning>
 
- <section>
- <title>File targets</title>
-
- <para>
- As described above, file targets corresponds
- to files that Boost.Build manages. User's may be concerned about
- file targets in three ways: when declaring file target types,
- when declaring transformations between types, and when
- determining where file target will be placed. File targets can
- also be connected with actions, that determine how the target is
- created. Both file targets and actions are implemented in the
- <literal>virtual-target</literal> module.
- </para>
-
- <section>
- <title>Types</title>
-
- <para>A file target can be given a file, which determines
- what transformations can be applied to the file. The
- <literal>type.register</literal> rule declares new types. File type can
- also be assigned a scanner, which is used to find implicit
- dependencies. See "dependency scanning" [ link? ] below.</para>
- </section>
- </section>
-
- <section>
- <title>Target paths</title>
-
- <para>To distinguish targets build with different properties, they
- are put in different directories. Rules for determining target
- paths are given below:</para>
-
- <orderedlist>
- <listitem>
- <simpara>
- All targets are placed under directory corresponding to the
- project where they are defined.
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- Each non free, non incidental property cause an additional
- element to be added to the target path. That element has the
- form <literal>&lt;feature-name&gt;-&lt;feature-value&gt;</literal> for
- ordinary features and <literal>&lt;feature-value&gt;</literal> for
- implicit ones. [Note about composite features].
- </simpara>
- </listitem>
-
- <listitem>
- <simpara>
- If the set of free, non incidental properties is different
- from the set of free, non incidental properties for the project
- in which the main target that uses the target is defined, a
- part of the form <literal>main_target-&lt;name&gt;</literal> is added to
- the target path. <emphasis role="bold">Note:</emphasis>It would be nice to completely
- track free features also, but this appears to be complex and
- not extremely needed.
- </simpara>
- </listitem>
- </orderedlist>
+ <section>
+ <title>File targets</title>
+
+ <para>
+ As described above, file targets correspond to files that Boost.Build
+ manages. Users may be concerned about file targets in three ways: when
+ declaring file target types, when declaring transformations between types
+ and when determining where a file target is to be placed. File targets can
+ also be connected to actions that determine how the target is to be created.
+ Both file targets and actions are implemented in the
+ <literal>virtual-target</literal> module.
+ </para>
+
+ <section>
+ <title>Types</title>
+
+ <para>
+ A file target can be given a type, which determines what transformations
+ can be applied to the file. The <literal>type.register</literal> rule
+ declares new types. File type can also be assigned a scanner, which is
+ then used to find implicit dependencies. See "<link
+ linkend="bbv2.arch.depends">dependency scanning</link>".
+ </para>
+ </section>
 
- <para>For example, we might have these paths:</para>
+ <section>
+ <title>Target paths</title>
 
+ <para>
+ To distinguish targets build with different properties, they are put in
+ different directories. Rules for determining target paths are given below:
+ </para>
+
+ <orderedlist>
+ <listitem><simpara>
+ All targets are placed under a directory corresponding to the project
+ where they are defined.
+ </simpara></listitem>
+
+ <listitem><simpara>
+ Each non free, non incidental property causes an additional element to
+ be added to the target path. That element has the the form
+ <literal>&lt;feature-name&gt;-&lt;feature-value&gt;</literal> for
+ ordinary features and <literal>&lt;feature-value&gt;</literal> for
+ implicit ones. [TODO: Add note about composite features].
+ </simpara></listitem>
+
+ <listitem><simpara>
+ If the set of free, non incidental properties is different from the
+ set of free, non incidental properties for the project in which the main
+ target that uses the target is defined, a part of the form
+ <literal>main_target-&lt;name&gt;</literal> is added to the target path.
+ <emphasis role="bold">Note:</emphasis>It would be nice to completely
+ track free features also, but this appears to be complex and not
+ extremely needed.
+ </simpara></listitem>
+ </orderedlist>
+
+ <para>
+ For example, we might have these paths:
 <programlisting>
 debug/optimization-off
 debug/main-target-a
 </programlisting>
-
- </section>
- </section>
- </section>
+ </para>
     </section>
+ </section>
+
   </appendix>
 
 <!--
      Local Variables:
      mode: xml
- sgml-indent-data: t
+ sgml-indent-data: t
      sgml-parent-document: ("userman.xml" "chapter")
      sgml-set-face: t
      End:

Modified: branches/release/tools/build/v2/doc/src/extending.xml
==============================================================================
--- branches/release/tools/build/v2/doc/src/extending.xml (original)
+++ branches/release/tools/build/v2/doc/src/extending.xml 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -169,7 +169,7 @@
 local a = [ new action $(source) : common.copy : $(property-set) ] ;
 local t = [ new file-target $(name) : CPP : $(project) : $(a) ] ;
 </programlisting>
- <para>The first line creates an instance of the <classname>action></classname> class.
+ <para>The first line creates an instance of the <classname>action</classname> class.
         The first parameter is the list of sources. The second parameter is the name
         a jam-level <link linkend="bbv2.overview.jam_language.actions">action</link>.
         The third parameter is the property-set applying to this action. The second line
@@ -181,8 +181,9 @@
         once with the same properties. Returning to different instance of <classname>file-target</classname>
         that correspond to the same file clearly will result in problems. Therefore, whenever
         returning targets you should pass them via the <code>virtual-target.register</code>
- function, that will replace targets with previously created identical ones, as
- necessary.<footnote><para>This create-then-register pattern is caused by limitations
+ function, besides allowing Boost Build to track which virtual targets
+ got created for each metatarget, this will also replace targets with previously created identical
+ ones, as necessary.<footnote><para>This create-then-register pattern is caused by limitations
         of the Boost.Jam language. Python port is likely to never create duplicate targets.</para></footnote>
         Here are a couple of examples:
 <programlisting>

Modified: branches/release/tools/build/v2/doc/src/overview.xml
==============================================================================
--- branches/release/tools/build/v2/doc/src/overview.xml (original)
+++ branches/release/tools/build/v2/doc/src/overview.xml 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -21,7 +21,7 @@
       <orderedlist>
         <listitem>
           <para>
- The Boost.Build executable tries to find Boost.Build modules and
+ The Boost.Build executable tries to find Boost.Build modules and
             loads the top-level module. The exact process is described in <xref linkend=
             "bbv2.reference.init"/>
           </para>
@@ -98,11 +98,11 @@
     g++ -o a.o -g a.c
 </programlisting>
         This is a rather low-level description mechanism and it's hard to adjust commands, options,
- and sets of created targets depending on the compiler and operating system used.
+ and sets of created targets depending on the compiler and operating system used.
       </para>
 
       <para>
- To improve portability, most modern build system provide a set of higher-level
+ To improve portability, most modern build system provide a set of higher-level
         functions that can be used in build description files. Consider this example:
 <programlisting>
 add_program ("a", "a.c")
@@ -112,7 +112,7 @@
         different command lines may be used. However, <code>add_program</code> is higher-level,
         but rather thin level. All targets are created immediately when the build description
         is parsed, which makes it impossible to perform multi-variant builds. Often, change
- in any build property requires a complete reconfiguration of the build tree.
+ in any build property requires a complete reconfiguration of the build tree.
       </para>
 
       <para>
@@ -121,7 +121,7 @@
         <indexterm> <primary>main target</primary> <see>metataget</see> </indexterm>
         <firstterm>metatarget</firstterm>&mdash;an object that is created when the build description
         is parsed and can be called later with specific build properties to generate
- actual targets.
+ actual targets.
       </para>
 
       <para>
@@ -154,7 +154,7 @@
       <para>
         The final concept is <indexterm><primary>property</primary><secondary>propagation</secondary></indexterm>
         <firstterm>property propagation</firstterm>. Boost.Build does not require that every
- metatarget is called with the same properties. Instead, the
+ metatarget is called with the same properties. Instead, the
         "top-level" metatargets are called with the properties specified on the command line.
         Each metatarget can elect to augment or override some properties (in particular,
         using the requirements mechanism, see <xref linkend="bbv2.overview.targets.requirements"/>).
@@ -163,10 +163,10 @@
         maybe in turn modify build properties and have dependencies of their own.
       </para>
 
- <para>For a more in-depth treatment of the requirements and concepts, you may refer
+ <para>For a more in-depth treatment of the requirements and concepts, you may refer
       to <ulink url="http://syrcose.ispras.ru/2009/files/04_paper.pdf">SYRCoSE 2009 Boost.Build article</ulink>.
       </para>
-
+
     </section>
 
     <section id="bbv2.overview.jam_language">
@@ -367,7 +367,7 @@
 }
 </programlisting>
         In this example, the rule checks if a certain build property is specified.
- If so, it sets the variable <varname>OPIONS</varname> that is then used
+ If so, it sets the variable <varname>OPTIONS</varname> that is then used
         inside the action. Note that the variables set "on a target" will be
         visible only inside actions building that target, not globally. Were
         they set globally, using variable named <varname>OPTIONS</varname> in
@@ -384,7 +384,7 @@
     <title>Configuration</title>
 
     <para>
- On startup, Boost.Build searches and reads two configuration files:
+ On startup, Boost.Build searches and reads two configuration files:
       <filename>site-config.jam</filename> and <filename>user-config.jam</filename>.
       The first one is usually installed and maintained by a system administrator, and
       the second is for the user to modify. You can edit the one in the top-level
@@ -392,49 +392,49 @@
       directory and edit the copy. The following table explains where both files
       are searched.
     </para>
-
+
     <table id="bbv2.reference.init.config">
       <title>Search paths for configuration files</title>
-
+
       <tgroup cols="3">
         <thead>
-
+
           <row>
             <entry></entry>
-
+
             <entry>site-config.jam</entry>
-
+
             <entry>user-config.jam</entry>
           </row>
-
+
         </thead>
         <tbody>
-
+
           <row>
             <entry>Linux</entry>
-
+
             <entry>
               <simpara><code>/etc</code></simpara>
               <simpara><code>$HOME</code></simpara>
               <simpara><code>$BOOST_BUILD_PATH</code></simpara>
             </entry>
-
+
             <entry>
               <simpara><code>$HOME</code></simpara>
               <simpara><code>$BOOST_BUILD_PATH</code></simpara>
             </entry>
           </row>
-
+
           <row>
             <entry>Windows</entry>
-
+
             <entry>
               <simpara><code>%SystemRoot%</code></simpara>
               <simpara><code>%HOMEDRIVE%%HOMEPATH%</code></simpara>
               <simpara><code>%HOME%</code></simpara>
               <simpara><code>%BOOST_BUILD_PATH%</code></simpara>
             </entry>
-
+
             <entry>
               <simpara><code>%HOMEDRIVE%%HOMEPATH%</code></simpara>
               <simpara><code>%HOME%</code></simpara>
@@ -444,8 +444,8 @@
         </tbody>
       </tgroup>
     </table>
-
- <tip>
+
+ <tip>
       <para>
         You can use the <command>--debug-configuration</command> option to
         find which configuration files are actually loaded.
@@ -552,7 +552,7 @@
       Many of toolsets have an <parameter class="function">options</parameter>
       parameter to fine-tune the configuration. All of
       Boost.Build's standard compiler toolsets accept four options
- <varname>cflags</varname>, <varname>cxxflags</varname>,
+ <varname>cflags</varname>, <varname>cxxflags</varname>,
       <varname>compileflags</varname> and <varname>linkflags</varname> as <parameter
       class="function">options</parameter> specifying flags that will be
       always passed to the corresponding tools. Values of the
@@ -604,7 +604,7 @@
         <varlistentry>
           <term>target</term>
 
- <listitem><para>All tokens that are neither options nor properties specify
+ <listitem><para>All tokens that are neither options nor properties specify
           what targets to build. The available targets entirely depend on the project
           you are building.</para></listitem>
         </varlistentry>
@@ -612,7 +612,7 @@
 
       <section id="bbv2.overview.invocation.examples">
         <title>Examples</title>
-
+
         <para>To build all targets defined in the Jamfile in the current directory with the default properties, run:
 <screen>
 b2
@@ -635,7 +635,7 @@
 
       <section id="bbv2.overview.invocation.options">
         <title>Options</title>
-
+
         <para>Boost.Build recognizes the following command line options.</para>
 
         <variablelist>
@@ -649,7 +649,7 @@
               </para>
             </listitem>
           </varlistentry>
-
+
           <varlistentry>
             <term><option>--clean</option></term>
             <listitem>
@@ -659,7 +659,7 @@
               together with target names to clean specific targets.</para>
             </listitem>
           </varlistentry>
-
+
           <varlistentry>
             <term><option>--clean-all</option></term>
             <listitem>
@@ -669,7 +669,7 @@
               </para>
             </listitem>
           </varlistentry>
-
+
           <varlistentry>
             <term><option>--build-dir</option></term>
             <listitem>
@@ -680,13 +680,35 @@
               specified in Jamroot, and the build dir specified in Jamroot
               (or <literal>bin</literal>, if none is specified).
               </para>
-
+
               <para>The option is primarily useful when building from read-only
               media, when you can't modify Jamroot.
               </para>
             </listitem>
           </varlistentry>
-
+
+ <varlistentry>
+ <term><option>--abbreviate-paths</option></term>
+ <listitem>
+ <para>Compresses target paths by abbreviating each component.
+ This option is useful to keep paths from becoming longer than
+ the filesystem supports. See also <xref linkend="bbv2.reference.buildprocess.targetpath"/>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--hash</option></term>
+ <listitem>
+ <para>Compresses target paths using an MD5 hash. This option is
+ useful to keep paths from becoming longer than the filesystem
+ supports. This option produces shorter paths than --abbreviate-paths
+ does, but at the cost of making them less understandable.
+ See also <xref linkend="bbv2.reference.buildprocess.targetpath"/>.
+ </para>
+ </listitem>
+ </varlistentry>
+
           <varlistentry>
             <term><option>--version</option></term>
             <listitem>
@@ -724,7 +746,7 @@
               <para>Run up to <replaceable>N</replaceable> commands in parallel.</para>
             </listitem>
           </varlistentry>
-
+
           <varlistentry>
             <term><option>--debug-configuration</option></term>
             <listitem>
@@ -732,7 +754,7 @@
               and toolset files.</para>
             </listitem>
           </varlistentry>
-
+
           <varlistentry>
             <term><option>--debug-building</option></term>
             <listitem>
@@ -740,7 +762,7 @@
               </para>
             </listitem>
           </varlistentry>
-
+
           <varlistentry>
             <term><option>--debug-generators</option></term>
             <listitem>
@@ -749,15 +771,6 @@
               </para>
             </listitem>
           </varlistentry>
-
- <varlistentry>
- <term><option>--ignore-config</option></term>
- <listitem>
- <para>Do not load <literal>site-config.jam</literal> or
- <literal>user-config.jam</literal>.
- </para>
- </listitem>
- </varlistentry>
 
           <varlistentry>
             <term><option>-d0</option></term>
@@ -769,7 +782,7 @@
           <varlistentry>
             <term><option>-d <replaceable>N</replaceable></option></term>
             <listitem>
- <para>Enable cummulative debugging levels from 1 to n. Values are:
+ <para>Enable cummulative debugging levels from 1 to n. Values are:
               <orderedlist>
                 <listitem>Show the actions taken for building targets, as they are executed (the default).</listitem>
                 <listitem>Show "quiet" actions and display all action text, as they are executed.</listitem>
@@ -823,53 +836,53 @@
         <para>In the simplest case, the build is performed with a single set of properties,
         that you specify on the command line with elements in the form
         <command><replaceable>feature</replaceable>=<replaceable>value</replaceable></command>.
- The complete list of features can be found in <xref linkend="bbv2.overview.builtins.features"/>.
+ The complete list of features can be found in <xref linkend="bbv2.overview.builtins.features"/>.
         The most common features are summarized below.</para>
 
         <table>
           <tgroup cols="3">
             <thead>
-
+
               <row>
                 <entry>Feature</entry>
-
+
                 <entry>Allowed values</entry>
-
+
                 <entry>Notes</entry>
               </row>
-
+
             </thead>
             <tbody>
-
+
               <row>
                 <entry>variant</entry>
-
+
                 <entry>debug,release</entry>
-
+
                 <entry></entry>
               </row>
 
               <row>
                 <entry>link</entry>
-
+
                 <entry>shared,static</entry>
-
+
                 <entry>Determines if Boost.Build creates shared or static libraries</entry>
               </row>
 
               <row>
                 <entry>threading</entry>
-
+
                 <entry>single,multi</entry>
-
+
                 <entry>Cause the produced binaries to be thread-safe. This requires proper support in the source code itself.</entry>
               </row>
 
               <row>
                 <entry>address-model</entry>
-
+
                 <entry>32,64</entry>
-
+
                 <entry>Explicitly request either 32-bit or 64-bit code generation. This typically
                 requires that your compiler is appropriately configured. Please refer to
                 <xref linkend="bbv2.reference.tools.compilers"/> and your compiler documentation
@@ -878,75 +891,75 @@
 
               <row>
                 <entry>toolset</entry>
-
+
                 <entry>(Depends on configuration)</entry>
-
+
                 <entry>The C++ compiler to use. See <xref linkend="bbv2.reference.tools.compilers"/> for a detailed list.</entry>
               </row>
 
               <row>
                 <entry>include</entry>
-
+
                 <entry>(Arbitrary string)</entry>
-
+
                 <entry>Additional include paths for C and C++ compilers.</entry>
               </row>
 
               <row>
                 <entry>define</entry>
-
+
                 <entry>(Arbitrary string)</entry>
-
+
                 <entry>Additional macro definitions for C and C++ compilers. The string should be either
                 <code>SYMBOL</code> or <code>SYMBOL=VALUE</code></entry>
               </row>
 
               <row>
                 <entry>cxxflags</entry>
-
+
                 <entry>(Arbitrary string)</entry>
-
+
                 <entry>Custom options to pass to the C++ compiler.</entry>
               </row>
 
               <row>
                 <entry>cflags</entry>
-
+
                 <entry>(Arbitrary string)</entry>
-
+
                 <entry>Custom options to pass to the C compiler.</entry>
               </row>
 
               <row>
                 <entry>linkflags</entry>
-
+
                 <entry>(Arbitrary string)</entry>
-
+
                 <entry>Custom options to pass to the C++ linker.</entry>
               </row>
 
               <row>
                 <entry>runtime-link</entry>
-
+
                 <entry>shared,static</entry>
-
+
                 <entry>Determines if shared or static version of C and C++ runtimes should be used.</entry>
               </row>
-
+
             </tbody>
- </tgroup>
+ </tgroup>
         </table>
 
         <para>If you have more than one version of a given C++ toolset (e.g. configured in
         <filename>user-config.jam</filename>, or autodetected, as happens with msvc), you can
- request the specific version by passing
+ request the specific version by passing
         <code><replaceable>toolset</replaceable>-<replaceable>version</replaceable></code> as
         the value of the <code>toolset</code> feature, for example <code>toolset=msvc-8.0</code>.
         </para>
 
 
         <para>
- If a feature has a fixed set of values it can be specified more than
+ If a feature has a fixed set of values it can be specified more than
           once on the command line. <!-- define 'base' and link to it -->
           In which case, everything will be built several times --
           once for each specified value of a feature. For example, if you use
@@ -955,7 +968,7 @@
 b2 link=static link=shared threading=single threading=multi
 </screen>
         <para>
- Then a total of 4 builds will be performed. For convenience,
+ Then a total of 4 builds will be performed. For convenience,
           instead of specifying all requested values of a feature in separate command line elements,
           you can separate the values with commas, for example:
         </para>
@@ -969,7 +982,7 @@
 b2 include=static,shared
 </screen>
         <para>is not treated specially.</para>
-
+
       </section>
 
       <section id="bbv2.overview.invocation.targets">

Modified: branches/release/tools/build/v2/doc/src/path.xml
==============================================================================
--- branches/release/tools/build/v2/doc/src/path.xml (original)
+++ branches/release/tools/build/v2/doc/src/path.xml 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,6 +7,7 @@
   <title>path</title>
   <indexterm>
     <primary>path</primary>
+ <secondary>module</secondary>
   </indexterm>
 
   <para>

Modified: branches/release/tools/build/v2/doc/src/reference.xml
==============================================================================
--- branches/release/tools/build/v2/doc/src/reference.xml (original)
+++ branches/release/tools/build/v2/doc/src/reference.xml 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -615,7 +615,7 @@
         </listitem>
       </varlistentry>
 
- <varlistentry><term><literal>tag</literal></term>
+ <varlistentry><term><anchor id="bbv2.builtin.features.tag"/><literal>tag</literal></term>
 
         <listitem><para>The <literal>tag</literal> feature is used to customize
         the name of the generated files. The value should have the form:
@@ -1463,6 +1463,83 @@
 
         </section>
 
+ <section id="bbv2.reference.tools.libraries.zlib">
+ <title>zlib</title>
+ <indexterm><primary>zlib</primary></indexterm>
+
+ <para>Provides support for the
+ <ulink url="http://www.zlib.net">zlib</ulink> library. zlib
+ can be configured either to use precompiled binaries or to
+ build the library from source.</para>
+
+ <para>zlib can be initialized using the following syntax</para>
+ <programlisting>
+using zlib : <optional><replaceable>version</replaceable></optional> : <optional><replaceable>options</replaceable></optional> : <optional><replaceable>condition</replaceable></optional> : <optional><replaceable>is-default</replaceable></optional> ;
+ </programlisting>
+ <para>Options for using a prebuilt library:</para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>search</literal></term>
+ <listitem>
+ <para>The directory containing the zlib binaries.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem>
+ <para>Overrides the default library name.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>include</literal></term>
+ <listitem>
+ <para>The directory containing the zlib headers.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>If none of these options is specified, then the environmental
+ variables ZLIB_LIBRARY_PATH, ZLIB_NAME, and ZLIB_INCLUDE will be
+ used instead.</para>
+ <para>Options for building zlib from source:</para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>source</literal></term>
+ <listitem>
+ <para>The zlib source directory. Defaults to the
+ environmental variable ZLIB_SOURCE.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>tag</literal></term>
+ <listitem>
+ <para>Sets the <link linkend="bbv2.builtin.features.tag">tag</link>
+ property to adjust the file name of the library. Ignored
+ when using precompiled binaries.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>build-name</literal></term>
+ <listitem>
+ <para>The base name to use for the compiled library.
+ Ignored when using precompiled binaries.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Examples:</para>
+ <programlisting>
+# Find zlib in the default system location
+using zlib ;
+# Build zlib from source
+using zlib : 1.2.7 : &lt;source&gt;/home/steven/zlib-1.2.7 ;
+# Find zlib in /usr/local
+using zlib : 1.2.7 : &lt;include&gt;/usr/local/include &lt;search&gt;/usr/local/lib ;
+# Build zlib from source for msvc and find
+# prebuilt binaries for gcc.
+using zlib : 1.2.7 : &lt;source&gt;C:/Devel/src/zlib-1.2.7 : &lt;toolset&gt;msvc ;
+using zlib : 1.2.7 : : &lt;toolset&gt;gcc ;
+</programlisting>
+ </section>
+
       </section>
 
       <section>
@@ -2089,6 +2166,7 @@
     
     <section id="bbv2.reference.buildprocess.targetpath">
       <title>Target Paths</title>
+ <indexterm><primary>path</primary><secondary>for targets</secondary></indexterm>
 
       <para>Several factors determine the location of a concrete
       file target. All files in a project are built under

Modified: branches/release/tools/build/v2/engine/build.bat
==============================================================================
--- branches/release/tools/build/v2/engine/build.bat (original)
+++ branches/release/tools/build/v2/engine/build.bat 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -463,13 +463,18 @@
 set YYACC_SOURCES=yyacc.c
 set MKJAMBASE_SOURCES=mkjambase.c
 set BJAM_SOURCES=
-set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c constants.c debug.c execnt.c filent.c function.c glob.c hash.c
-set BJAM_SOURCES=%BJAM_SOURCES% hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c
-set BJAM_SOURCES=%BJAM_SOURCES% object.c option.c output.c parse.c pathunix.c regexp.c
-set BJAM_SOURCES=%BJAM_SOURCES% rules.c scan.c search.c subst.c timestamp.c variable.c modules.c
-set BJAM_SOURCES=%BJAM_SOURCES% strings.c filesys.c builtins.c md5.c pwd.c class.c w32_getreg.c native.c
-set BJAM_SOURCES=%BJAM_SOURCES% modules/set.c modules/path.c modules/regex.c
-set BJAM_SOURCES=%BJAM_SOURCES% modules/property-set.c modules/sequence.c modules/order.c
+set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c constants.c debug.c
+set BJAM_SOURCES=%BJAM_SOURCES% execcmd.c execnt.c filent.c frames.c function.c
+set BJAM_SOURCES=%BJAM_SOURCES% glob.c hash.c hdrmacro.c headers.c jam.c
+set BJAM_SOURCES=%BJAM_SOURCES% jambase.c jamgram.c lists.c make.c make1.c
+set BJAM_SOURCES=%BJAM_SOURCES% object.c option.c output.c parse.c pathnt.c
+set BJAM_SOURCES=%BJAM_SOURCES% pathsys.c regexp.c rules.c scan.c search.c
+set BJAM_SOURCES=%BJAM_SOURCES% subst.c timestamp.c variable.c modules.c
+set BJAM_SOURCES=%BJAM_SOURCES% strings.c filesys.c builtins.c md5.c class.c
+set BJAM_SOURCES=%BJAM_SOURCES% cwd.c w32_getreg.c native.c modules/set.c
+set BJAM_SOURCES=%BJAM_SOURCES% modules/path.c modules/regex.c
+set BJAM_SOURCES=%BJAM_SOURCES% modules/property-set.c modules/sequence.c
+set BJAM_SOURCES=%BJAM_SOURCES% modules/order.c
 
 set BJAM_UPDATE=
 :Check_Update

Modified: branches/release/tools/build/v2/engine/build.jam
==============================================================================
--- branches/release/tools/build/v2/engine/build.jam (original)
+++ branches/release/tools/build/v2/engine/build.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,19 +1,20 @@
 #~ Copyright 2002-2007 Rene Rivera.
 #~ 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)
+#~ (See accompanying file LICENSE_1_0.txt or copy at
+#~ http://www.boost.org/LICENSE_1_0.txt)
 
 # Clean env vars of any "extra" empty values.
 for local v in ARGV CC CFLAGS LIBS
 {
- local values ;
- for local x in $($(v))
- {
- if $(x) != ""
- {
- values += $(x) ;
- }
- }
- $(v) = $(values) ;
+ local values ;
+ for local x in $($(v))
+ {
+ if $(x) != ""
+ {
+ values += $(x) ;
+ }
+ }
+ $(v) = $(values) ;
 }
 
 # Platform related specifics.
@@ -139,9 +140,8 @@
     toolset-root = $(toolset-root:J="") ;
 }
 
-# Configure the implemented toolsets. These are minimal
-# commands and options to compile the full Jam. When
-# adding new toolsets make sure to add them to the
+# Configure the implemented toolsets. These are minimal commands and options to
+# compile the full Jam. When adding new toolsets make sure to add them to the
 # "known" list also.
 
 rule toolset ( name command .type ? : opt.out + : opt.define * : flags * : linklibs * )
@@ -258,8 +258,9 @@
     : -L$(--python-lib[1]) -l$(--python-lib[2]) ;
 ## Metrowerks CodeWarrior 8.x
 {
- # Even though CW can compile all files at once, it crashes if it tries in the bjam case.
- local mwcc = ; if $(OS) = NT { mwcc = mwcc ; } else { mwcc = mwc$(OSPLAT:L) ; }
+ # Even though CW can compile all files at once, it crashes if it tries in
+ # the bjam case.
+ local mwcc ; if $(OS) != NT { mwcc = mwc$(OSPLAT:L) ; }
     mwcc ?= mwcc ;
     toolset metrowerks $(mwcc) : "-o " : -D
         : -c -lang c -subsystem console -cwd include
@@ -372,11 +373,11 @@
     : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
 toolset vc11 cl : /Fe /Fe /Fd /Fo : -D
     : /nologo
- [ opt --release : /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ]
+ [ opt --release : /GL /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ]
     [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
     -I$(--python-include) -I$(--extra-include)
     : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
-
+
 # First set the build commands and options according to the
 # preset toolset.
 toolset = [ MATCH --toolset=(.*) : $(ARGV) ] ;
@@ -472,25 +473,21 @@
 
 if --show-locate-target in $(ARGV)
 {
- ECHO $(locate-target) ;
+ ECHO $(locate-target) ;
 }
 
 # We have some different files for UNIX, and NT.
 jam.source =
- command.c compile.c constants.c debug.c function.c glob.c
- hash.c hcache.c headers.c hdrmacro.c
- jam.c jambase.c jamgram.c
- lists.c make.c make1.c mem.c object.c
- option.c output.c parse.c regexp.c rules.c
- scan.c search.c subst.c w32_getreg.c
- timestamp.c variable.c modules.c strings.c filesys.c
- builtins.c pwd.c class.c native.c md5.c modules/set.c
- modules/path.c modules/regex.c modules/property-set.c
- modules/sequence.c modules/order.c
- ;
+ command.c compile.c constants.c debug.c execcmd.c frames.c function.c glob.c
+ hash.c hcache.c headers.c hdrmacro.c jam.c jambase.c jamgram.c lists.c
+ make.c make1.c mem.c object.c option.c output.c parse.c pathsys.c regexp.c
+ rules.c scan.c search.c subst.c w32_getreg.c timestamp.c variable.c
+ modules.c strings.c filesys.c builtins.c class.c cwd.c native.c md5.c
+ modules/set.c modules/path.c modules/regex.c modules/property-set.c
+ modules/sequence.c modules/order.c ;
 if $(OS) = NT
 {
- jam.source += execnt.c filent.c pathunix.c ;
+ jam.source += execnt.c filent.c pathnt.c ;
 }
 else
 {
@@ -593,7 +590,7 @@
     .mkdir $(locate-target) ;
     if $(--link)
     {
- local objs = ;
+ local objs ;
         for local s in $(>)
         {
             # Translate any subdir elements into a simple file name.
@@ -710,7 +707,8 @@
 
 yacc ?= [ GLOB $(PATH) : yacc$(SUFEXE) ] ;
 yacc ?= [ GLOB $(PATH) : bison$(SUFEXE) ] ;
-yacc ?= [ GLOB "$(ProgramFiles:J= )\\GnuWin32\\bin" "C:\\Program Files\\GnuWin32\\bin" : bison$(SUFEXE) ] ;
+yacc ?= [ GLOB "$(ProgramFiles:J= )\\GnuWin32\\bin"
+ "C:\\Program Files\\GnuWin32\\bin" : bison$(SUFEXE) ] ;
 yacc = $(yacc[1]) ;
 switch $(yacc:D=:S=)
 {
@@ -748,7 +746,8 @@
 } }
 if $(grammar) && ! $(yacc)
 {
- EXIT "Could not find the 'yacc' tool, and therefore can not build the grammar." ;
+ EXIT Could not find the 'yacc' tool, and therefore can not build the
+ grammar. ;
 }
 if $(grammar) && $(yacc)
 {
@@ -778,7 +777,7 @@
 {
     $(>).exe = [ .exe $(>) : $(jam.source) ] ;
     DEPENDS all : $($(>).exe) ;
-
+
     # Make a copy under the old name.
     $(<).exe = $(<:S=$($(>).exe:S)) ;
     LOCATE on $($(<).exe) = $(locate-target) ;
@@ -789,29 +788,33 @@
 
 
 # Scan sources for header dependencies.
-# WARNING: Yes those are *REAL TABS* below. DO NOT CHANGE,
-# under any circumstances, to spaces!! And the tabs
-# indenting this are so that if someone is in the mood to
-# replace tabs they hit this comment, and hopefully notice
-# their error.
-rule .scan
-{
- HDRRULE on $(<:D=) = .hdr.scan ;
- HDRSCAN on $(<:D=) = "^[ ]*#[ ]*include[ ]*([<\"][^\">]*[\">]).*$" ;
-}
-rule .hdr.scan
-{
- local hdrs = [ GLOB . : $(>:D=) ] ;
- INCLUDES $(<:D=) : $(hdrs:D=) ;
- HDRRULE on $(>:D=) = .hdr.scan ;
- HDRSCAN on $(>:D=) = "^[ ]*#[ ]*include[ ]*([<\"][^\">]*[\">]).*$" ;
-}
-.scan [ GLOB . : *.c ] ;
-
-# Distribution making from here on out. Assumes that
-# the docs are already built as html at ../doc/html. If
-# they aren't, then the docs are not included in the dist
-# archive.
+#
+# In order to keep things simple, we made a slight compromise here - we only
+# detect changes in headers included relative to the current folder as opposed
+# to those included from somewhere on the include path.
+rule .scan ( targets + )
+{
+ HDRRULE on $(targets) = .hdr.scan ;
+ HDRSCAN on $(targets) = "^[ \t]*#[ \t]*include[ \t]*\"([^\"]*)\".*$" ;
+}
+rule .hdr.scan ( target : includes * : binding )
+{
+ local target-path = [ NORMALIZE_PATH $(binding:D) ] ;
+ # Extra grist provides target name uniqueness when referencing same name
+ # header files from different folders.
+ local include-targets = <$(target-path)>$(includes) ;
+ NOCARE $(include-targets) ;
+ INCLUDES $(target) : $(include-targets) ;
+ SEARCH on $(include-targets) = $(target-path) ;
+ ISFILE $(include-targets) ;
+ .scan $(include-targets) ;
+}
+.scan $(jam.source) ;
+
+
+# Distribution making from here on out. Assumes that the docs are already built
+# as HTML at ../doc/html. Otherwise they will not be included in the built
+# distribution archive.
 dist.license =
     [ GLOB . : $(LICENSE).txt ]
     ;
@@ -866,16 +869,16 @@
     switch $(zip:D=:S=)
     {
         case 7z* : zip += a -r -tzip -mx=9 ;
- case zip : zip += -9r ;
+ case zip : zip += -9r ;
     }
     actions piecemeal [PACK] {
- "$(zip)" "$(<)" "$(>)"
+ "$(zip)" "$(<)" "$(>)"
     }
     actions piecemeal [ZIP] {
- "$(zip)" "$(<)" "$(>)"
+ "$(zip)" "$(<)" "$(>)"
     }
     actions piecemeal [COPY] {
- copy /Y "$(>)" "$(<)" >NUL:
+ copy /Y "$(>)" "$(<)" >NUL:
     }
 }
 if $(UNIX) = true
@@ -888,23 +891,23 @@
         case * : tar += -c -f - ;
     }
     actions [PACK] {
- "$(tar)" "$(>)" | gzip -c9 > "$(<)"
+ "$(tar)" "$(>)" | gzip -c9 > "$(<)"
     }
     #~ actions [PACK] {
- #~ tar cf "$(<:S=.tar)" "$(>)"
+ #~ tar cf "$(<:S=.tar)" "$(>)"
     #~ }
     actions [ZIP] {
     gzip -c9 "$(>)" > "$(<)"
     }
     actions [COPY] {
- cp -Rpf "$(>)" "$(<)"
+ cp -Rpf "$(>)" "$(<)"
     }
 }
 
 # The single binary, compressed.
 rule .binary
 {
- local zip = ;
+ local zip ;
     if $(OS) = NT { zip = $($(<).exe:S=.zip) ; }
     if $(UNIX) = true { zip = $($(<).exe:S=.tgz) ; }
     zip = $(zip:S=)-$(VERSION)-$(RELEASE)-$(platform)$(zip:S) ;
@@ -937,7 +940,7 @@
         }
     }
 
- local pack = ;
+ local pack ;
     if $(OS) = NT { pack = $(dst-dir).zip ; }
     if $(UNIX) = true { pack = $(dst-dir).tgz ; }
 
@@ -966,7 +969,7 @@
 rpm-tool = $(rpm-tool[1]) ;
 rule .rpm ( name : source )
 {
- local rpm-arch = ;
+ local rpm-arch ;
     switch $(OSPLAT)
     {
         case X86 : rpm-arch ?= i386 ;
@@ -999,8 +1002,8 @@
     rm -f rpm.out
 }
 
-# The distribution targets. Don't bother with the targets if
-# distribution build not requested.
+# The distribution targets. Do not bother with them unless this is a
+# distribution build.
 if dist in $(ARGV)
 {
     #~ .binary bjam ;

Modified: branches/release/tools/build/v2/engine/build.sh
==============================================================================
--- branches/release/tools/build/v2/engine/build.sh (original)
+++ branches/release/tools/build/v2/engine/build.sh 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,13 +2,14 @@
 
 #~ Copyright 2002-2005 Rene Rivera.
 #~ 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)
+#~ (See accompanying file LICENSE_1_0.txt or copy at
+#~ http://www.boost.org/LICENSE_1_0.txt)
 
 # Reset the toolset.
 BOOST_JAM_TOOLSET=
 
-# Run a command, and echo before doing so. Also checks the exit
-# status and quits if there was an error.
+# Run a command, and echo before doing so. Also checks the exit status and quits
+# if there was an error.
 echo_run ()
 {
     echo "$@"
@@ -35,7 +36,7 @@
     echo "### A special toolset; cc, is available which is used as a fallback"
     echo "### when a more specific toolset is not found and the cc command is"
     echo "### detected. The 'cc' toolset will use the CC, CFLAGS, and LIBS"
- echo "### envrironment variables, if present."
+ echo "### environment variables, if present."
     echo "###"
     exit 1
 }
@@ -153,11 +154,10 @@
         BOOST_JAM_TOOLSET_ROOT=/opt/intel/compiler50/ia32/
     fi
     if test -r ${BOOST_JAM_TOOLSET_ROOT}bin/iccvars.sh ; then
- # iccvars doesn't change LD_RUN_PATH. We adjust LD_RUN_PATH
- # here in order not to have to rely on ld.so.conf knowing the
- # icc library directory. We do this before running iccvars.sh
- # in order to allow a user to add modifications to LD_RUN_PATH
- # in iccvars.sh.
+ # iccvars does not change LD_RUN_PATH. We adjust LD_RUN_PATH here in
+ # order not to have to rely on ld.so.conf knowing the icc library
+ # directory. We do this before running iccvars.sh in order to allow a
+ # user to add modifications to LD_RUN_PATH in iccvars.sh.
         if test -z "${LD_RUN_PATH}"; then
             LD_RUN_PATH="${BOOST_JAM_TOOLSET_ROOT}lib"
         else
@@ -245,13 +245,13 @@
 YYACC_SOURCES="yyacc.c"
 MKJAMBASE_SOURCES="mkjambase.c"
 BJAM_SOURCES="\
- command.c compile.c constants.c debug.c function.c glob.c hash.c\
- hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c\
- object.c option.c output.c parse.c pathunix.c regexp.c\
- rules.c scan.c search.c subst.c timestamp.c variable.c modules.c\
- strings.c filesys.c builtins.c pwd.c class.c native.c md5.c w32_getreg.c\
- modules/set.c modules/path.c modules/regex.c modules/property-set.c\
- modules/sequence.c modules/order.c"
+ command.c compile.c constants.c debug.c execcmd.c frames.c function.c glob.c\
+ hash.c hdrmacro.c headers.c jam.c jambase.c jamgram.c lists.c make.c make1.c\
+ object.c option.c output.c parse.c pathsys.c pathunix.c regexp.c rules.c\
+ scan.c search.c subst.c timestamp.c variable.c modules.c strings.c filesys.c\
+ builtins.c class.c cwd.c native.c md5.c w32_getreg.c modules/set.c\
+ modules/path.c modules/regex.c modules/property-set.c modules/sequence.c\
+ modules/order.c"
 case $BOOST_JAM_TOOLSET in
     mingw)
     BJAM_SOURCES="${BJAM_SOURCES} execnt.c filent.c"
@@ -263,7 +263,7 @@
 esac
 
 BJAM_UPDATE=
-if test "$1" = "--update" -o "$2" = "--update" -o "$3" = "--update" -o "$4" = "--update" ; then
+if test "$1" = "--update" -o "$2" = "--update" -o "$3" = "--update" -o "$4" = "--update" ; then
     BJAM_UPDATE="update"
 fi
 if test "${BJAM_UPDATE}" = "update" -a ! -x "./bootstrap/jam0" ; then

Modified: branches/release/tools/build/v2/engine/builtins.c
==============================================================================
--- branches/release/tools/build/v2/engine/builtins.c (original)
+++ branches/release/tools/build/v2/engine/builtins.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,27 +5,28 @@
  */
 
 #include "jam.h"
-
-#include "lists.h"
-#include "parse.h"
 #include "builtins.h"
-#include "rules.h"
+
+#include "compile.h"
+#include "constants.h"
+#include "cwd.h"
 #include "filesys.h"
-#include "object.h"
-#include "regexp.h"
 #include "frames.h"
 #include "hash.h"
-#include "strings.h"
-#include "pwd.h"
-#include "pathsys.h"
-#include "make.h"
 #include "hdrmacro.h"
-#include "compile.h"
+#include "lists.h"
+#include "make.h"
+#include "md5.h"
 #include "native.h"
-#include "variable.h"
+#include "object.h"
+#include "parse.h"
+#include "pathsys.h"
+#include "rules.h"
+#include "strings.h"
+#include "subst.h"
 #include "timestamp.h"
-#include "md5.h"
-#include "constants.h"
+#include "variable.h"
+
 #include <ctype.h>
 
 #if defined(USE_EXECUNIX)
@@ -33,10 +34,10 @@
 # include <sys/wait.h>
 #else
 /*
- NT does not have wait() and associated macros, it uses the return value
- of system() instead. Status code group are documented at
- http://msdn.microsoft.com/en-gb/library/ff565436.aspx
-*/
+ * NT does not have wait() and associated macros and uses the system() return
+ * value instead. Status code group are documented at:
+ * http://msdn.microsoft.com/en-gb/library/ff565436.aspx
+ */
 # define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0)
 # define WEXITSTATUS(w)(w)
 #endif
@@ -45,19 +46,30 @@
  * builtins.c - builtin jam rules
  *
  * External routines:
- *
- * load_builtin() - define builtin rules
+ * load_builtins() - define builtin rules
+ * unknown_rule() - reports an unknown rule occurrence to the
+ * user and exits
  *
  * Internal routines:
- *
- * builtin_depends() - DEPENDS/INCLUDES rule.
- * builtin_echo() - ECHO rule.
- * builtin_exit() - EXIT rule.
- * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule.
- * builtin_glob() - GLOB rule.
- * builtin_match() - MATCH rule.
- *
- * 01/10/01 (seiwald) - split from compile.c
+ * append_if_exists() - if file exists, append it to the list
+ * builtin_calc() - CALC rule
+ * builtin_delete_module() - DELETE_MODULE ( MODULE ? )
+ * builtin_depends() - DEPENDS/INCLUDES rule
+ * builtin_echo() - ECHO rule
+ * builtin_exit() - EXIT rule
+ * builtin_export() - EXPORT ( MODULE ? : RULES * )
+ * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
+ * builtin_glob() - GLOB rule
+ * builtin_glob_recursive() - ???
+ * builtin_hdrmacro() - ???
+ * builtin_import() - IMPORT rule
+ * builtin_match() - MATCH rule, regexp matching
+ * builtin_rebuilds() - REBUILDS rule
+ * builtin_rulenames() - RULENAMES ( MODULE ? )
+ * builtin_split_by_characters() - splits the given string into tokens
+ * builtin_varnames() - VARNAMES ( MODULE ? )
+ * get_source_line() - get a frame's file and line number
+ * information
  */
 
 
@@ -73,14 +85,15 @@
     LIST * builtin_system_registry_names( FRAME *, int );
 #endif
 
-int glob( const char * s, const char * c );
+int glob( char const * s, char const * c );
 
 void backtrace ( FRAME * );
 void backtrace_line ( FRAME * );
 void print_source_line( FRAME * );
 
 
-RULE * bind_builtin( const char * name_, LIST * (* f)( FRAME *, int flags ), int flags, const char * * args )
+RULE * bind_builtin( char const * name_, LIST * (* f)( FRAME *, int flags ),
+ int flags, char const * * args )
 {
     FUNCTION * func;
     RULE * result;
@@ -98,7 +111,7 @@
 }
 
 
-RULE * duplicate_rule( const char * name_, RULE * other )
+RULE * duplicate_rule( char const * name_, RULE * other )
 {
     OBJECT * name = object_new( name_ );
     RULE * result = import_rule( other, root_module(), name );
@@ -107,6 +120,10 @@
 }
 
 
+/*
+ * load_builtins() - define builtin rules
+ */
+
 void load_builtins()
 {
     duplicate_rule( "Always",
@@ -123,7 +140,7 @@
                     builtin_echo, 0, 0 ) ) );
 
     {
- const char * args[] = { "message", "*", ":", "result-value", "?", 0 };
+ char const * args[] = { "message", "*", ":", "result-value", "?", 0 };
         duplicate_rule( "exit",
         duplicate_rule( "Exit",
           bind_builtin( "EXIT",
@@ -131,13 +148,14 @@
     }
 
     {
- const char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
+ char const * args[] = { "directories", "*", ":", "patterns", "*", ":",
+ "case-insensitive", "?", 0 };
         duplicate_rule( "Glob",
                         bind_builtin( "GLOB", builtin_glob, 0, args ) );
     }
 
     {
- const char * args[] = { "patterns", "*", 0 };
+ char const * args[] = { "patterns", "*", 0 };
         bind_builtin( "GLOB-RECURSIVELY",
                       builtin_glob_recursive, 0, args );
     }
@@ -147,7 +165,8 @@
                     builtin_depends, 1, 0 ) );
 
     {
- const char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
+ char const * args[] = { "targets", "*", ":", "targets-to-rebuild", "*",
+ 0 };
         bind_builtin( "REBUILDS",
                       builtin_rebuilds, 0, args );
     }
@@ -161,9 +180,9 @@
                     builtin_match, 0, 0 ) );
 
     {
- const char * args[] = { "string", ":", "delimiters" };
- bind_builtin( "SPLIT_BY_CHARACTERS",
- builtin_split_by_characters, 0, 0 );
+ char const * args[] = { "string", ":", "delimiters", 0 };
+ bind_builtin( "SPLIT_BY_CHARACTERS",
+ builtin_split_by_characters, 0, args );
     }
 
     duplicate_rule( "NoCare",
@@ -194,231 +213,233 @@
      * action should be inverted (ok <=> fail) this can be useful when
      * performing test runs from Jamfiles.
      */
- bind_builtin( "FAIL_EXPECTED",
- builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
+ bind_builtin( "FAIL_EXPECTED",
+ builtin_flags, T_FLAG_FAIL_EXPECTED, 0 );
 
- bind_builtin( "RMOLD",
- builtin_flags, T_FLAG_RMOLD, 0 );
+ bind_builtin( "RMOLD",
+ builtin_flags, T_FLAG_RMOLD, 0 );
 
- {
- const char * args[] = { "targets", "*", 0 };
- bind_builtin( "UPDATE",
- builtin_update, 0, args );
- }
+ {
+ char const * args[] = { "targets", "*", 0 };
+ bind_builtin( "UPDATE",
+ builtin_update, 0, args );
+ }
 
- {
- const char * args[] = { "targets", "*",
+ {
+ char const * args[] = { "targets", "*",
                             ":", "log", "?",
- ":", "ignore-minus-n", "?",
+ ":", "ignore-minus-n", "?",
                             ":", "ignore-minus-q", "?", 0 };
- bind_builtin( "UPDATE_NOW",
- builtin_update_now, 0, args );
- }
-
- {
- const char * args[] = { "string", "pattern", "replacements", "+", 0 };
- duplicate_rule( "subst",
- bind_builtin( "SUBST",
- builtin_subst, 0, args ) );
- }
-
- {
- const char * args[] = { "module", "?", 0 };
- bind_builtin( "RULENAMES",
- builtin_rulenames, 0, args );
- }
-
-
- {
- const char * args[] = { "module", "?", 0 };
- bind_builtin( "VARNAMES",
- builtin_varnames, 0, args );
- }
-
- {
- const char * args[] = { "module", "?", 0 };
- bind_builtin( "DELETE_MODULE",
- builtin_delete_module, 0, args );
- }
+ bind_builtin( "UPDATE_NOW",
+ builtin_update_now, 0, args );
+ }
+
+ {
+ char const * args[] = { "string", "pattern", "replacements", "+", 0 };
+ duplicate_rule( "subst",
+ bind_builtin( "SUBST",
+ builtin_subst, 0, args ) );
+ }
+
+ {
+ char const * args[] = { "module", "?", 0 };
+ bind_builtin( "RULENAMES",
+ builtin_rulenames, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", "?", 0 };
+ bind_builtin( "VARNAMES",
+ builtin_varnames, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", "?", 0 };
+ bind_builtin( "DELETE_MODULE",
+ builtin_delete_module, 0, args );
+ }
 
- {
- const char * args[] = { "source_module", "?",
+ {
+ char const * args[] = { "source_module", "?",
                             ":", "source_rules", "*",
                             ":", "target_module", "?",
                             ":", "target_rules", "*",
                             ":", "localize", "?", 0 };
- bind_builtin( "IMPORT",
- builtin_import, 0, args );
- }
-
- {
- const char * args[] = { "module", "?", ":", "rules", "*", 0 };
- bind_builtin( "EXPORT",
- builtin_export, 0, args );
- }
-
- {
- const char * args[] = { "levels", "?", 0 };
- bind_builtin( "CALLER_MODULE",
- builtin_caller_module, 0, args );
- }
-
- {
- const char * args[] = { "levels", "?", 0 };
- bind_builtin( "BACKTRACE",
- builtin_backtrace, 0, args );
- }
-
- {
- const char * args[] = { 0 };
- bind_builtin( "PWD",
- builtin_pwd, 0, args );
- }
-
- {
- const char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
- bind_builtin( "IMPORT_MODULE",
- builtin_import_module, 0, args );
- }
-
- {
- const char * args[] = { "module", "?", 0 };
- bind_builtin( "IMPORTED_MODULES",
- builtin_imported_modules, 0, args );
- }
-
- {
- const char * args[] = { "instance_module", ":", "class_module", 0 };
- bind_builtin( "INSTANCE",
- builtin_instance, 0, args );
- }
-
- {
- const char * args[] = { "sequence", "*", 0 };
- bind_builtin( "SORT",
- builtin_sort, 0, args );
- }
-
- {
- const char * args[] = { "path_parts", "*", 0 };
- bind_builtin( "NORMALIZE_PATH",
- builtin_normalize_path, 0, args );
- }
-
- {
- const char * args[] = { "args", "*", 0 };
- bind_builtin( "CALC",
- builtin_calc, 0, args );
- }
-
- {
- const char * args[] = { "module", ":", "rule", 0 };
- bind_builtin( "NATIVE_RULE",
- builtin_native_rule, 0, args );
- }
-
- {
- const char * args[] = { "module", ":", "rule", ":", "version", 0 };
- bind_builtin( "HAS_NATIVE_RULE",
- builtin_has_native_rule, 0, args );
- }
-
- {
- const char * args[] = { "module", "*", 0 };
- bind_builtin( "USER_MODULE",
- builtin_user_module, 0, args );
- }
-
- {
- const char * args[] = { 0 };
- bind_builtin( "NEAREST_USER_LOCATION",
- builtin_nearest_user_location, 0, args );
- }
-
- {
- const char * args[] = { "file", 0 };
- bind_builtin( "CHECK_IF_FILE",
- builtin_check_if_file, 0, args );
- }
+ bind_builtin( "IMPORT",
+ builtin_import, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", "?", ":", "rules", "*", 0 };
+ bind_builtin( "EXPORT",
+ builtin_export, 0, args );
+ }
+
+ {
+ char const * args[] = { "levels", "?", 0 };
+ bind_builtin( "CALLER_MODULE",
+ builtin_caller_module, 0, args );
+ }
+
+ {
+ char const * args[] = { "levels", "?", 0 };
+ bind_builtin( "BACKTRACE",
+ builtin_backtrace, 0, args );
+ }
+
+ {
+ char const * args[] = { 0 };
+ bind_builtin( "PWD",
+ builtin_pwd, 0, args );
+ }
+
+ {
+ char const * args[] = { "modules_to_import", "+",
+ ":", "target_module", "?", 0 };
+ bind_builtin( "IMPORT_MODULE",
+ builtin_import_module, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", "?", 0 };
+ bind_builtin( "IMPORTED_MODULES",
+ builtin_imported_modules, 0, args );
+ }
+
+ {
+ char const * args[] = { "instance_module", ":", "class_module", 0 };
+ bind_builtin( "INSTANCE",
+ builtin_instance, 0, args );
+ }
+
+ {
+ char const * args[] = { "sequence", "*", 0 };
+ bind_builtin( "SORT",
+ builtin_sort, 0, args );
+ }
+
+ {
+ char const * args[] = { "path_parts", "*", 0 };
+ bind_builtin( "NORMALIZE_PATH",
+ builtin_normalize_path, 0, args );
+ }
+
+ {
+ char const * args[] = { "args", "*", 0 };
+ bind_builtin( "CALC",
+ builtin_calc, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", ":", "rule", 0 };
+ bind_builtin( "NATIVE_RULE",
+ builtin_native_rule, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", ":", "rule", ":", "version", 0 };
+ bind_builtin( "HAS_NATIVE_RULE",
+ builtin_has_native_rule, 0, args );
+ }
+
+ {
+ char const * args[] = { "module", "*", 0 };
+ bind_builtin( "USER_MODULE",
+ builtin_user_module, 0, args );
+ }
+
+ {
+ char const * args[] = { 0 };
+ bind_builtin( "NEAREST_USER_LOCATION",
+ builtin_nearest_user_location, 0, args );
+ }
+
+ {
+ char const * args[] = { "file", 0 };
+ bind_builtin( "CHECK_IF_FILE",
+ builtin_check_if_file, 0, args );
+ }
 
 #ifdef HAVE_PYTHON
- {
- const char * args[] = { "python-module", ":", "function", ":",
- "jam-module", ":", "rule-name", 0 };
- bind_builtin( "PYTHON_IMPORT_RULE",
- builtin_python_import_rule, 0, args );
- }
+ {
+ char const * args[] = { "python-module",
+ ":", "function",
+ ":", "jam-module",
+ ":", "rule-name", 0 };
+ bind_builtin( "PYTHON_IMPORT_RULE",
+ builtin_python_import_rule, 0, args );
+ }
 #endif
 
 # if defined( OS_NT ) || defined( OS_CYGWIN )
- {
- const char * args[] = { "key_path", ":", "data", "?", 0 };
- bind_builtin( "W32_GETREG",
- builtin_system_registry, 0, args );
- }
-
- {
- const char * args[] = { "key_path", ":", "result-type", 0 };
- bind_builtin( "W32_GETREGNAMES",
- builtin_system_registry_names, 0, args );
- }
+ {
+ char const * args[] = { "key_path", ":", "data", "?", 0 };
+ bind_builtin( "W32_GETREG",
+ builtin_system_registry, 0, args );
+ }
+
+ {
+ char const * args[] = { "key_path", ":", "result-type", 0 };
+ bind_builtin( "W32_GETREGNAMES",
+ builtin_system_registry_names, 0, args );
+ }
 # endif
 
- {
- const char * args[] = { "command", ":", "*", 0 };
- duplicate_rule( "SHELL",
- bind_builtin( "COMMAND",
- builtin_shell, 0, args ) );
- }
-
- {
- const char * args[] = { "string", 0 };
- bind_builtin( "MD5",
- builtin_md5, 0, args ) ;
- }
-
- {
- const char * args[] = { "name", ":", "mode", 0 };
- bind_builtin( "FILE_OPEN",
- builtin_file_open, 0, args );
- }
-
- {
- const char * args[] = { "string", ":", "width", 0 };
- bind_builtin( "PAD",
- builtin_pad, 0, args );
- }
-
- {
- const char * args[] = { "targets", "*", 0 };
- bind_builtin( "PRECIOUS",
- builtin_precious, 0, args );
- }
-
- {
- const char * args [] = { 0 };
- bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
- }
-
- {
- const char * args [] = { "path", 0 };
- bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
- }
-
- /* Initialize builtin modules. */
- init_set();
- init_path();
- init_regex();
- init_property_set();
- init_sequence();
- init_order();
+ {
+ char const * args[] = { "command", ":", "*", 0 };
+ duplicate_rule( "SHELL",
+ bind_builtin( "COMMAND",
+ builtin_shell, 0, args ) );
+ }
+
+ {
+ char const * args[] = { "string", 0 };
+ bind_builtin( "MD5",
+ builtin_md5, 0, args );
+ }
+
+ {
+ char const * args[] = { "name", ":", "mode", 0 };
+ bind_builtin( "FILE_OPEN",
+ builtin_file_open, 0, args );
+ }
+
+ {
+ char const * args[] = { "string", ":", "width", 0 };
+ bind_builtin( "PAD",
+ builtin_pad, 0, args );
+ }
+
+ {
+ char const * args[] = { "targets", "*", 0 };
+ bind_builtin( "PRECIOUS",
+ builtin_precious, 0, args );
+ }
+
+ {
+ char const * args [] = { 0 };
+ bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
+ }
+
+ {
+ char const * args [] = { "path", 0 };
+ bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
+ }
+
+ /* Initialize builtin modules. */
+ init_set();
+ init_path();
+ init_regex();
+ init_property_set();
+ init_sequence();
+ init_order();
 }
 
 
 /*
- * builtin_calc() - CALC rule.
+ * builtin_calc() - CALC rule
  *
- * The CALC rule performs simple mathematical operations on two arguments.
+ * Performs simple mathematical operations on two arguments.
  */
 
 LIST * builtin_calc( FRAME * frame, int flags )
@@ -429,11 +450,12 @@
     long lhs_value;
     long rhs_value;
     long result_value;
- char buffer [ 16 ];
+ char buffer[ 16 ];
     char const * lhs;
     char const * op;
     char const * rhs;
- LISTITER iter = list_begin( arg ), end = list_end( arg );
+ LISTITER iter = list_begin( arg );
+ LISTITER const end = list_end( arg );
 
     if ( iter == end ) return L0;
     lhs = object_str( list_item( iter ) );
@@ -449,18 +471,12 @@
     lhs_value = atoi( lhs );
     rhs_value = atoi( rhs );
 
- if ( strcmp( "+", op ) == 0 )
- {
+ if ( !strcmp( "+", op ) )
         result_value = lhs_value + rhs_value;
- }
- else if ( strcmp( "-", op ) == 0 )
- {
+ else if ( !strcmp( "-", op ) )
         result_value = lhs_value - rhs_value;
- }
     else
- {
         return L0;
- }
 
     sprintf( buffer, "%ld", result_value );
     result = list_push_back( result, object_new( buffer ) );
@@ -469,7 +485,7 @@
 
 
 /*
- * builtin_depends() - DEPENDS/INCLUDES rule.
+ * builtin_depends() - DEPENDS/INCLUDES rule
  *
  * The DEPENDS/INCLUDES builtin rule appends each of the listed sources on the
  * dependency/includes list of each of the listed targets. It binds both the
@@ -478,38 +494,37 @@
 
 LIST * builtin_depends( FRAME * frame, int flags )
 {
- LIST * targets = lol_get( frame->args, 0 );
- LIST * sources = lol_get( frame->args, 1 );
- LISTITER iter, end;
-
- iter = list_begin( targets ), end = list_end( targets );
+ LIST * const targets = lol_get( frame->args, 0 );
+ LIST * const sources = lol_get( frame->args, 1 );
+
+ LISTITER iter = list_begin( targets );
+ LISTITER end = list_end( targets );
     for ( ; iter != end; iter = list_next( iter ) )
     {
- TARGET * t = bindtarget( list_item( iter ) );
-
- /* If doing INCLUDES, switch to the TARGET's include */
- /* TARGET, creating it if needed. The internal include */
- /* TARGET shares the name of its parent. */
+ TARGET * const t = bindtarget( list_item( iter ) );
 
         if ( flags )
- {
- if ( !t->includes )
- {
- t->includes = copytarget( t );
- t->includes->original_target = t;
- }
- t = t->includes;
- }
-
- t->depends = targetlist( t->depends, sources );
+ target_include_many( t, sources );
+ else
+ t->depends = targetlist( t->depends, sources );
     }
 
     /* Enter reverse links */
- iter = list_begin( sources ), end = list_end( sources );
+ iter = list_begin( sources );
+ end = list_end( sources );
     for ( ; iter != end; iter = list_next( iter ) )
     {
- TARGET * s = bindtarget( list_item( iter ) );
- s->dependants = targetlist( s->dependants, targets );
+ TARGET * const s = bindtarget( list_item( iter ) );
+ if ( flags )
+ {
+ LISTITER t_iter = list_begin( targets );
+ LISTITER const t_end = list_end( targets );
+ for ( ; t_iter != t_end; t_iter = list_next( t_iter ) )
+ s->dependants = targetentry( s->dependants, bindtarget(
+ list_item( t_iter ) )->includes );
+ }
+ else
+ s->dependants = targetlist( s->dependants, targets );
     }
 
     return L0;
@@ -517,34 +532,31 @@
 
 
 /*
- * builtin_rebuilds() - REBUILDS rule.
+ * builtin_rebuilds() - REBUILDS rule
  *
- * The REBUILDS builtin rule appends each of the listed rebuild-targets in its
- * 2nd argument on the rebuilds list of each of the listed targets in its first
- * argument.
+ * Appends each of the rebuild-targets listed in its second argument to the
+ * rebuilds list for each of the targets listed in its first argument.
  */
 
 LIST * builtin_rebuilds( FRAME * frame, int flags )
 {
     LIST * targets = lol_get( frame->args, 0 );
     LIST * rebuilds = lol_get( frame->args, 1 );
- LISTITER iter = list_begin( targets ), end = list_end( targets );
-
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
     for ( ; iter != end; iter = list_next( iter ) )
     {
- TARGET * t = bindtarget( list_item( iter ) );
+ TARGET * const t = bindtarget( list_item( iter ) );
         t->rebuilds = targetlist( t->rebuilds, rebuilds );
     }
-
     return L0;
 }
 
 
 /*
- * builtin_echo() - ECHO rule.
+ * builtin_echo() - ECHO rule
  *
- * The ECHO builtin rule echoes the targets to the user. No other actions are
- * taken.
+ * Echoes the targets to the user. No other actions are taken.
  */
 
 LIST * builtin_echo( FRAME * frame, int flags )
@@ -557,40 +569,36 @@
 
 
 /*
- * builtin_exit() - EXIT rule.
+ * builtin_exit() - EXIT rule
  *
- * The EXIT builtin rule echoes the targets to the user and exits the program
- * with a failure status.
+ * Echoes the targets to the user and exits the program with a failure status.
  */
 
 LIST * builtin_exit( FRAME * frame, int flags )
 {
- LIST * code = lol_get( frame->args, 1 );
+ LIST * const code = lol_get( frame->args, 1 );
     list_print( lol_get( frame->args, 0 ) );
     printf( "\n" );
     if ( !list_empty( code ) )
- {
         exit( atoi( object_str( list_front( code ) ) ) );
- }
     else
- {
         exit( EXITBAD ); /* yeech */
- }
     return L0;
 }
 
 
 /*
- * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule.
+ * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
  *
- * Builtin_flags() marks the target with the appropriate flag, for use by make0().
- * It binds each target as a TARGET.
+ * Marks the target with the appropriate flag, for use by make0(). It binds each
+ * target as a TARGET.
  */
 
 LIST * builtin_flags( FRAME * frame, int flags )
 {
- LIST * l = lol_get( frame->args, 0 );
- LISTITER iter = list_begin( l ), end = list_end( l );
+ LIST * const targets = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
     for ( ; iter != end; iter = list_next( iter ) )
         bindtarget( list_item( iter ) )->flags |= flags;
     return L0;
@@ -598,7 +606,7 @@
 
 
 /*
- * builtin_globbing() - GLOB rule.
+ * builtin_glob() - GLOB rule
  */
 
 struct globbing
@@ -616,21 +624,16 @@
 }
 
 
-static void builtin_glob_back
-(
- void * closure,
- OBJECT * file,
- int status,
- time_t time
-)
+static void builtin_glob_back( void * closure, OBJECT * file, int status,
+ timestamp const * const time )
 {
     PROFILE_ENTER( BUILTIN_GLOB_BACK );
 
- struct globbing * globbing = (struct globbing *)closure;
- LIST * l;
- PATHNAME f;
- string buf[ 1 ];
- LISTITER iter, end;
+ struct globbing * const globbing = (struct globbing *)closure;
+ PATHNAME f;
+ string buf[ 1 ];
+ LISTITER iter;
+ LISTITER end;
 
     /* Null out directory for matching. We wish we had file_dirscan() pass up a
      * PATHNAME.
@@ -650,17 +653,19 @@
     }
 
     string_new( buf );
- path_build( &f, buf, 0 );
+ path_build( &f, buf );
 
     if ( globbing->case_insensitive )
         downcase_inplace( buf->value );
 
- iter = list_begin( globbing->patterns ), end = list_end( globbing->patterns );
+ iter = list_begin( globbing->patterns );
+ end = list_end( globbing->patterns );
     for ( ; iter != end; iter = list_next( iter ) )
     {
         if ( !glob( object_str( list_item( iter ) ), buf->value ) )
         {
- globbing->results = list_push_back( globbing->results, object_copy( file ) );
+ globbing->results = list_push_back( globbing->results, object_copy(
+ file ) );
             break;
         }
     }
@@ -674,7 +679,8 @@
 static LIST * downcase_list( LIST * in )
 {
     LIST * result = L0;
- LISTITER iter = list_begin( in ), end = list_end( in );
+ LISTITER iter = list_begin( in );
+ LISTITER const end = list_end( in );
 
     string s[ 1 ];
     string_new( s );
@@ -694,26 +700,28 @@
 
 LIST * builtin_glob( FRAME * frame, int flags )
 {
- LIST * l = lol_get( frame->args, 0 );
- LIST * r = lol_get( frame->args, 1 );
+ LIST * const l = lol_get( frame->args, 0 );
+ LIST * const r = lol_get( frame->args, 1 );
 
- LISTITER iter, end;
+ LISTITER iter;
+ LISTITER end;
     struct globbing globbing;
 
     globbing.results = L0;
     globbing.patterns = r;
 
- globbing.case_insensitive
+ globbing.case_insensitive =
 # if defined( OS_NT ) || defined( OS_CYGWIN )
- = l; /* Always case-insensitive if any files can be found. */
+ l; /* Always case-insensitive if any files can be found. */
 # else
- = lol_get( frame->args, 2 );
+ lol_get( frame->args, 2 );
 # endif
 
     if ( globbing.case_insensitive )
         globbing.patterns = downcase_list( r );
 
- iter = list_begin( l ), end = list_end( l );
+ iter = list_begin( l );
+ end = list_end( l );
     for ( ; iter != end; iter = list_next( iter ) )
         file_dirscan( list_item( iter ), builtin_glob_back, &globbing );
 
@@ -724,30 +732,27 @@
 }
 
 
-static int has_wildcards( char const * str )
+static int has_wildcards( char const * const str )
 {
- size_t const index = strcspn( str, "[]*?" );
- return str[ index ] == '\0' ? 0 : 1;
+ return str[ strcspn( str, "[]*?" ) ] ? 1 : 0;
 }
 
 
 /*
- * If 'file' exists, append 'file' to 'list'. Returns 'list'.
+ * append_if_exists() - if file exists, append it to the list
  */
 
 static LIST * append_if_exists( LIST * list, OBJECT * file )
 {
- time_t time;
- timestamp( file, &time );
- return time > 0
+ return file_query( file )
         ? list_push_back( list, object_copy( file ) )
- : list;
+ : list ;
 }
 
 
 LIST * glob1( OBJECT * dirname, OBJECT * pattern )
 {
- LIST * plist = list_new( object_copy(pattern) );
+ LIST * const plist = list_new( object_copy( pattern ) );
     struct globbing globbing;
 
     globbing.results = L0;
@@ -774,7 +779,7 @@
 }
 
 
-LIST * glob_recursive( const char * pattern )
+LIST * glob_recursive( char const * pattern )
 {
     LIST * result = L0;
 
@@ -782,7 +787,7 @@
     if ( !has_wildcards( pattern ) )
     {
         /* No metacharacters. Check if the path exists. */
- OBJECT * p = object_new( pattern );
+ OBJECT * const p = object_new( pattern );
         result = append_if_exists( result, p );
         object_free( p );
     }
@@ -807,7 +812,7 @@
             path->f_grist.len = 0;
             path->f_dir.ptr = 0;
             path->f_dir.len = 0;
- path_build( path, basename, 0 );
+ path_build( path, basename );
 
             dirs = has_wildcards( dirname->value )
                 ? glob_recursive( dirname->value )
@@ -815,15 +820,18 @@
 
             if ( has_wildcards( basename->value ) )
             {
- OBJECT * b = object_new( basename->value );
- LISTITER iter = list_begin( dirs ), end = list_end( dirs );
+ OBJECT * const b = object_new( basename->value );
+ LISTITER iter = list_begin( dirs );
+ LISTITER const end = list_end( dirs );
                 for ( ; iter != end; iter = list_next( iter ) )
- result = list_append( result, glob1( list_item( iter ), b ) );
+ result = list_append( result, glob1( list_item( iter ), b )
+ );
                 object_free( b );
             }
             else
             {
- LISTITER iter = list_begin( dirs ), end = list_end( dirs );
+ LISTITER iter = list_begin( dirs );
+ LISTITER const end = list_end( dirs );
                 string file_string[ 1 ];
                 string_new( file_string );
 
@@ -833,7 +841,7 @@
                     OBJECT * p;
                     path->f_dir.ptr = object_str( list_item( iter ) );
                     path->f_dir.len = strlen( object_str( list_item( iter ) ) );
- path_build( path, file_string, 0 );
+ path_build( path, file_string );
 
                     p = object_new( file_string->value );
 
@@ -854,8 +862,8 @@
         }
         else
         {
- /** No directory, just a pattern. */
- OBJECT * p = object_new( pattern );
+ /* No directory, just a pattern. */
+ OBJECT * const p = object_new( pattern );
             result = list_append( result, glob1( constant_dot, p ) );
             object_free( p );
         }
@@ -865,19 +873,25 @@
 }
 
 
+/*
+ * builtin_glob_recursive() - ???
+ */
+
 LIST * builtin_glob_recursive( FRAME * frame, int flags )
 {
     LIST * result = L0;
- LIST * l = lol_get( frame->args, 0 );
- LISTITER iter = list_begin( l ), end = list_end( l );
+ LIST * const l = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
     for ( ; iter != end; iter = list_next( iter ) )
- result = list_append( result, glob_recursive( object_str( list_item( iter ) ) ) );
+ result = list_append( result, glob_recursive( object_str( list_item(
+ iter ) ) ) );
     return result;
 }
 
 
 /*
- * builtin_match() - MATCH rule, regexp matching.
+ * builtin_match() - MATCH rule, regexp matching
  */
 
 LIST * builtin_match( FRAME * frame, int flags )
@@ -885,7 +899,10 @@
     LIST * l;
     LIST * r;
     LIST * result = L0;
- LISTITER l_iter, l_end, r_iter, r_end;
+ LISTITER l_iter;
+ LISTITER l_end;
+ LISTITER r_iter;
+ LISTITER r_end;
 
     string buf[ 1 ];
     string_new( buf );
@@ -893,15 +910,17 @@
     /* For each pattern */
 
     l = lol_get( frame->args, 0 );
- l_iter = list_begin( l ), l_end = list_end( l );
- for (; l_iter != l_end; l_iter = list_next( l_iter ) )
+ l_iter = list_begin( l );
+ l_end = list_end( l );
+ for ( ; l_iter != l_end; l_iter = list_next( l_iter ) )
     {
         /* Result is cached and intentionally never freed. */
         regexp * re = regex_compile( list_item( l_iter ) );
 
         /* For each string to match against. */
         r = lol_get( frame->args, 1 );
- r_iter = list_begin( r ), r_end = list_end( r );
+ r_iter = list_begin( r );
+ r_end = list_end( r );
         for ( ; r_iter != r_end; r_iter = list_next( r_iter ) )
         {
             if ( regexec( re, object_str( list_item( r_iter ) ) ) )
@@ -931,21 +950,26 @@
     return result;
 }
 
+
+/*
+ * builtin_split_by_characters() - splits the given string into tokens
+ */
+
 LIST * builtin_split_by_characters( FRAME * frame, int flags )
 {
     LIST * l1 = lol_get( frame->args, 0 );
     LIST * l2 = lol_get( frame->args, 1 );
 
     LIST * result = L0;
-
+
     string buf[ 1 ];
 
- const char * delimiters = object_str( list_front( l2 ) );
+ char const * delimiters = object_str( list_front( l2 ) );
     char * t;
 
     string_copy( buf, object_str( list_front( l1 ) ) );
 
- t = strtok( buf->value, delimiters) ;
+ t = strtok( buf->value, delimiters );
     while ( t )
     {
         result = list_push_back( result, object_new( t ) );
@@ -957,29 +981,35 @@
     return result;
 }
 
+
+/*
+ * builtin_hdrmacro() - ???
+ */
+
 LIST * builtin_hdrmacro( FRAME * frame, int flags )
 {
- LIST * l = lol_get( frame->args, 0 );
- LISTITER iter = list_begin( l ), end = list_end( l );
+ LIST * const l = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
 
- for ( ; iter != end; iter = list_next( iter ) )
- {
- TARGET * t = bindtarget( list_item( iter ) );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ TARGET * const t = bindtarget( list_item( iter ) );
 
- /* Scan file for header filename macro definitions. */
- if ( DEBUG_HEADER )
- printf( "scanning '%s' for header file macro definitions\n",
- object_str( list_item( iter ) ) );
+ /* Scan file for header filename macro definitions. */
+ if ( DEBUG_HEADER )
+ printf( "scanning '%s' for header file macro definitions\n",
+ object_str( list_item( iter ) ) );
 
- macro_headers( t );
- }
+ macro_headers( t );
+ }
 
- return L0;
+ return L0;
 }
 
 
 /*
- * builtin_rulenames() - RULENAMES ( MODULE ? ).
+ * builtin_rulenames() - RULENAMES ( MODULE ? )
  *
  * Returns a list of the non-local rule names in the given MODULE. If MODULE is
  * not supplied, returns the list of rule names in the global module.
@@ -987,8 +1017,8 @@
 
 static void add_rule_name( void * r_, void * result_ )
 {
- RULE * r = (RULE *)r_;
- LIST * * result = (LIST * *)result_;
+ RULE * const r = (RULE *)r_;
+ LIST * * const result = (LIST * *)result_;
     if ( r->exported )
         *result = list_push_back( *result, object_copy( r->name ) );
 }
@@ -998,7 +1028,9 @@
 {
     LIST * arg0 = lol_get( frame->args, 0 );
     LIST * result = L0;
- module_t * source_module = bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 );
+ module_t * const source_module = bindmodule( list_empty( arg0 )
+ ? 0
+ : list_front( arg0 ) );
 
     if ( source_module->rules )
         hashenumerate( source_module->rules, add_rule_name, &result );
@@ -1007,7 +1039,7 @@
 
 
 /*
- * builtin_varnames() - VARNAMES ( MODULE ? ).
+ * builtin_varnames() - VARNAMES ( MODULE ? )
  *
  * Returns a list of the variable names in the given MODULE. If MODULE is not
  * supplied, returns the list of variable names in the global module.
@@ -1027,10 +1059,11 @@
 {
     LIST * arg0 = lol_get( frame->args, 0 );
     LIST * result = L0;
- module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
-
- struct hash * vars = source_module->variables;
+ module_t * source_module = bindmodule( list_empty( arg0 )
+ ? 0
+ : list_front( arg0 ) );
 
+ struct hash * const vars = source_module->variables;
     if ( vars )
         hashenumerate( vars, add_hash_key, &result );
     return result;
@@ -1038,40 +1071,47 @@
 
 
 /*
- * builtin_delete_module() - MODULE ?.
+ * builtin_delete_module() - DELETE_MODULE ( MODULE ? )
  *
  * Clears all rules and variables from the given module.
  */
 
 LIST * builtin_delete_module( FRAME * frame, int flags )
 {
- LIST * arg0 = lol_get( frame->args, 0 );
- LIST * result = L0;
- module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
+ LIST * const arg0 = lol_get( frame->args, 0 );
+ module_t * const source_module = bindmodule( list_empty( arg0 ) ? 0 :
+ list_front( arg0 ) );
     delete_module( source_module );
- return result;
+ return L0;
 }
 
 
-static void unknown_rule( FRAME * frame, const char * key, module_t * module, OBJECT * rule_name )
+/*
+ * unknown_rule() - reports an unknown rule occurrence to the user and exits
+ */
+
+void unknown_rule( FRAME * frame, char const * key, module_t * module,
+ OBJECT * rule_name )
 {
- const char * module_name = module->name ? object_str( module->name ) : "";
     backtrace_line( frame->prev );
+ if ( key )
+ printf("%s error", key);
+ else
+ printf("ERROR");
+ printf( ": rule \"%s\" unknown in ", object_str( rule_name ) );
     if ( module->name )
- {
- printf( "%s error: rule \"%s\" unknown in module \"%s.\"\n", key, object_str( rule_name ), object_str( module->name ) );
- }
+ printf( "module \"%s\".\n", object_str( module->name ) );
     else
- {
- printf( "%s error: rule \"%s\" unknown in module \"\"\n", key, object_str( rule_name ) );
- }
+ printf( "root module.\n" );
     backtrace( frame->prev );
     exit( 1 );
 }
 
 
 /*
- * builtin_import() - IMPORT
+ * builtin_import() - IMPORT rule
+ *
+ * IMPORT
  * (
  * SOURCE_MODULE ? :
  * SOURCE_RULES * :
@@ -1080,11 +1120,11 @@
  * LOCALIZE ?
  * )
  *
- * The IMPORT rule imports rules from the SOURCE_MODULE into the TARGET_MODULE
- * as local rules. If either SOURCE_MODULE or TARGET_MODULE is not supplied, it
- * refers to the global module. SOURCE_RULES specifies which rules from the
- * SOURCE_MODULE to import; TARGET_RULES specifies the names to give those rules
- * in TARGET_MODULE. If SOURCE_RULES contains a name which doesn't correspond to
+ * Imports rules from the SOURCE_MODULE into the TARGET_MODULE as local rules.
+ * If either SOURCE_MODULE or TARGET_MODULE is not supplied, it refers to the
+ * global module. SOURCE_RULES specifies which rules from the SOURCE_MODULE to
+ * import; TARGET_RULES specifies the names to give those rules in
+ * TARGET_MODULE. If SOURCE_RULES contains a name that does not correspond to
  * a rule in SOURCE_MODULE, or if it contains a different number of items than
  * TARGET_RULES, an error is issued. If LOCALIZE is specified, the rules will be
  * executed in TARGET_MODULE, with corresponding access to its module local
@@ -1099,13 +1139,17 @@
     LIST * target_rules = lol_get( frame->args, 3 );
     LIST * localize = lol_get( frame->args, 4 );
 
- module_t * target_module =
- bindmodule( !list_empty( target_module_list ) ? list_front( target_module_list ) : 0 );
- module_t * source_module =
- bindmodule( !list_empty( source_module_list ) ? list_front( source_module_list ) : 0 );
-
- LISTITER source_iter = list_begin( source_rules ), source_end = list_end( source_rules );
- LISTITER target_iter = list_begin( target_rules ), target_end = list_end( target_rules );
+ module_t * target_module = bindmodule( list_empty( target_module_list )
+ ? 0
+ : list_front( target_module_list ) );
+ module_t * source_module = bindmodule( list_empty( source_module_list )
+ ? 0
+ : list_front( source_module_list ) );
+
+ LISTITER source_iter = list_begin( source_rules );
+ LISTITER const source_end = list_end( source_rules );
+ LISTITER target_iter = list_begin( target_rules );
+ LISTITER const target_end = list_end( target_rules );
 
     for ( ;
           source_iter != source_end && target_iter != target_end;
@@ -1115,9 +1159,10 @@
         RULE * r;
         RULE * imported;
 
- if ( !source_module->rules ||
- !(r = (RULE *)hash_find( source_module->rules, list_item( source_iter ) ) ) )
- unknown_rule( frame, "IMPORT", source_module, list_item( source_iter ) );
+ if ( !source_module->rules || !(r = (RULE *)hash_find(
+ source_module->rules, list_item( source_iter ) ) ) )
+ unknown_rule( frame, "IMPORT", source_module, list_item( source_iter
+ ) );
 
         imported = import_rule( r, target_module, list_item( target_iter ) );
         if ( !list_empty( localize ) )
@@ -1131,7 +1176,8 @@
     if ( source_iter != source_end || target_iter != target_end )
     {
         backtrace_line( frame->prev );
- printf( "import error: length of source and target rule name lists don't match!\n" );
+ printf( "import error: length of source and target rule name lists "
+ "don't match!\n" );
         printf( " source: " );
         list_print( source_rules );
         printf( "\n target: " );
@@ -1146,7 +1192,7 @@
 
 
 /*
- * builtin_export() - EXPORT ( MODULE ? : RULES * ).
+ * builtin_export() - EXPORT ( MODULE ? : RULES * )
  *
  * The EXPORT rule marks RULES from the SOURCE_MODULE as non-local (and thus
  * exportable). If an element of RULES does not name a rule in MODULE, an error
@@ -1155,18 +1201,19 @@
 
 LIST * builtin_export( FRAME * frame, int flags )
 {
- LIST * module_list = lol_get( frame->args, 0 );
- LIST * rules = lol_get( frame->args, 1 );
- module_t * m = bindmodule( !list_empty( module_list ) ? list_front( module_list ) : 0 );
+ LIST * const module_list = lol_get( frame->args, 0 );
+ LIST * const rules = lol_get( frame->args, 1 );
+ module_t * const m = bindmodule( list_empty( module_list ) ? 0 : list_front(
+ module_list ) );
 
- LISTITER iter = list_begin( rules ), end = list_end( rules );
+ LISTITER iter = list_begin( rules );
+ LISTITER const end = list_end( rules );
     for ( ; iter != end; iter = list_next( iter ) )
     {
         RULE * r;
-
- if ( !m->rules || !(r = (RULE *)hash_find( m->rules, list_item( iter ) ) ) )
+ if ( !m->rules || !( r = (RULE *)hash_find( m->rules, list_item( iter )
+ ) ) )
             unknown_rule( frame, "EXPORT", m, list_item( iter ) );
-
         r->exported = 1;
     }
     return L0;
@@ -1174,16 +1221,18 @@
 
 
 /*
- * get_source_line() - Retrieve the file and line number that should be
- * indicated for a given procedure in debug output or an error backtrace.
+ * get_source_line() - get a frame's file and line number information
+ *
+ * This is the execution traceback information to be indicated for in debug
+ * output or an error backtrace.
  */
 
-static void get_source_line( FRAME * frame, const char * * file, int * line )
+static void get_source_line( FRAME * frame, char const * * file, int * line )
 {
     if ( frame->file )
     {
- const char * f = object_str( frame->file );
- int l = frame->line;
+ char const * f = object_str( frame->file );
+ int l = frame->line;
         if ( !strcmp( f, "+" ) )
         {
             f = "jambase.c";
@@ -1202,9 +1251,8 @@
 
 void print_source_line( FRAME * frame )
 {
- const char * file;
- int line;
-
+ char const * file;
+ int line;
     get_source_line( frame, &file, &line );
     if ( line < 0 )
         printf( "(builtin):" );
@@ -1254,16 +1302,18 @@
 
 LIST * builtin_backtrace( FRAME * frame, int flags )
 {
- LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : (int)( (unsigned int)(-1) >> 1 ) ;
+ LIST * const levels_arg = lol_get( frame->args, 0 );
+ int levels = list_empty( levels_arg )
+ ? (int)( (unsigned int)(-1) >> 1 )
+ : atoi( object_str( list_front( levels_arg ) ) );
 
     LIST * result = L0;
- for ( ; ( frame = frame->prev ) && levels ; --levels )
+ for ( ; ( frame = frame->prev ) && levels; --levels )
     {
- const char * file;
- int line;
- char buf[32];
- string module_name[1];
+ char const * file;
+ int line;
+ char buf[ 32 ];
+ string module_name[ 1 ];
         get_source_line( frame, &file, &line );
         sprintf( buf, "%d", line );
         string_new( module_name );
@@ -1296,17 +1346,18 @@
 
 LIST * builtin_caller_module( FRAME * frame, int flags )
 {
- LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : 0 ;
+ LIST * const levels_arg = lol_get( frame->args, 0 );
+ int const levels = list_empty( levels_arg )
+ ? 0
+ : atoi( object_str( list_front( levels_arg ) ) );
 
     int i;
     for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
         frame = frame->prev;
 
- if ( frame->module == root_module() )
- return L0;
- else
- return list_new( object_copy( frame->module->name ) );
+ return frame->module == root_module()
+ ? L0
+ : list_new( object_copy( frame->module->name ) );
 }
 
 
@@ -1318,7 +1369,7 @@
 
 LIST * builtin_pwd( FRAME * frame, int flags )
 {
- return pwd();
+ return list_new( object_copy( cwd() ) );
 }
 
 
@@ -1340,13 +1391,17 @@
 extern int anyhow;
 int last_update_now_status;
 
-/* Takes a list of target names as first argument, and immediately
- updates them.
- Second parameter, if specified, if the descriptor (converted to a string)
- of a log file where all build output is redirected.
- Third parameter, if non-empty, specifies that the -n option should have
- no effect -- that is, all out-of-date targets should be rebuild.
-*/
+/* Takes a list of target names and immediately updates them.
+ *
+ * Parameters:
+ * 1. Target list.
+ * 2. Optional file descriptor (converted to a string) for a log file where all
+ * the related build output should be redirected.
+ * 3. If specified, makes the build temporarily disable the -n option, i.e.
+ * forces all needed out-of-date targets to be rebuilt.
+ * 4. If specified, makes the build temporarily disable the -q option, i.e.
+ * forces the build to continue even if one of the targets fails to build.
+ */
 LIST * builtin_update_now( FRAME * frame, int flags )
 {
     LIST * targets = lol_get( frame->args, 0 );
@@ -1358,24 +1413,21 @@
     int original_stderr = 0;
     int original_noexec = 0;
     int original_quitquick = 0;
-
 
     if ( !list_empty( log ) )
     {
- int fd = atoi( object_str( list_front( log ) ) );
- /* Redirect stdout and stderr, temporary, to the log file. */
+ /* Temporarily redirect stdout and stderr to the given log file. */
+ int const fd = atoi( object_str( list_front( log ) ) );
         original_stdout = dup( 0 );
         original_stderr = dup( 1 );
- dup2 ( fd, 0 );
- dup2 ( fd, 1 );
+ dup2( fd, 0 );
+ dup2( fd, 1 );
     }
 
     if ( !list_empty( force ) )
     {
         original_noexec = globs.noexec;
         globs.noexec = 0;
- original_quitquick = globs.quitquick;
- globs.quitquick = 0;
     }
 
     if ( !list_empty( continue_ ) )
@@ -1389,7 +1441,6 @@
     if ( !list_empty( force ) )
     {
         globs.noexec = original_noexec;
- globs.quitquick = original_quitquick;
     }
 
     if ( !list_empty( continue_ ) )
@@ -1399,8 +1450,9 @@
 
     if ( !list_empty( log ) )
     {
- /* Flush whatever stdio might have buffered, while descriptions
- 0 and 1 still refer to the log file. */
+ /* Flush whatever stdio might have buffered, while descriptions 0 and 1
+ * still refer to the log file.
+ */
         fflush( stdout );
         fflush( stderr );
         dup2( original_stdout, 0 );
@@ -1410,19 +1462,18 @@
     }
 
     last_update_now_status = status;
-
- if ( status == 0 )
- return list_new( object_copy( constant_ok ) );
- else
- return L0;
+
+ return status ? L0 : list_new( object_copy( constant_ok ) );
 }
 
 
 LIST * builtin_import_module( FRAME * frame, int flags )
 {
- LIST * arg1 = lol_get( frame->args, 0 );
- LIST * arg2 = lol_get( frame->args, 1 );
- module_t * m = !list_empty( arg2 ) ? bindmodule( list_front( arg2 ) ) : root_module();
+ LIST * const arg1 = lol_get( frame->args, 0 );
+ LIST * const arg2 = lol_get( frame->args, 1 );
+ module_t * const m = list_empty( arg2 )
+ ? root_module()
+ : bindmodule( list_front( arg2 ) );
     import_module( arg1, m );
     return L0;
 }
@@ -1430,8 +1481,9 @@
 
 LIST * builtin_imported_modules( FRAME * frame, int flags )
 {
- LIST * arg0 = lol_get( frame->args, 0 );
- return imported_modules( bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 ) );
+ LIST * const arg0 = lol_get( frame->args, 0 );
+ OBJECT * const module = list_empty( arg0 ) ? 0 : list_front( arg0 );
+ return imported_modules( bindmodule( module ) );
 }
 
 
@@ -1449,8 +1501,7 @@
 
 LIST * builtin_sort( FRAME * frame, int flags )
 {
- LIST * arg1 = lol_get( frame->args, 0 );
- return list_sort( arg1 );
+ return list_sort( lol_get( frame->args, 0 ) );
 }
 
 
@@ -1459,23 +1510,24 @@
     LIST * arg = lol_get( frame->args, 0 );
 
     /* First, we iterate over all '/'-separated elements, starting from the end
- * of string. If we see a '..', we remove a previous path elements. If we
- * see '.', we remove it. The removal is done by overwriting data using '\1'
- * in the string. After the whole string has been processed, we do a second
- * pass, removing all the entered '\1' characters.
+ * of string. If we see a '..', we remove a preceeding path element. If we
+ * see '.', we remove it. Removal is done by overwriting data using '\1'
+ * characters. After the whole string has been processed, we do a second
+ * pass, removing any entered '\1' characters.
      */
 
     string in[ 1 ];
     string out[ 1 ];
- /* Last character of the part of string still to be processed. */
+ /* Last character of the part of string still to be processed. */
     char * end;
- /* Working pointer. */
+ /* Working pointer. */
     char * current;
- /* Number of '..' elements seen and not processed yet. */
+ /* Number of '..' elements seen and not processed yet. */
     int dotdots = 0;
     int rooted = 0;
     OBJECT * result = 0;
- LISTITER arg_iter = list_begin( arg ), arg_end = list_end( arg );
+ LISTITER arg_iter = list_begin( arg );
+ LISTITER arg_end = list_end( arg );
 
     /* Make a copy of input: we should not change it. Prepend a '/' before it as
      * a guard for the algorithm later on and remember whether it was originally
@@ -1488,8 +1540,8 @@
         if ( object_str( list_item( arg_iter ) )[ 0 ] != '\0' )
         {
             if ( in->size == 1 )
- rooted = ( ( object_str( list_item( arg_iter ) )[ 0 ] == '/' ) ||
- ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' ) );
+ rooted = ( object_str( list_item( arg_iter ) )[ 0 ] == '/' ) ||
+ ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' );
             else
                 string_append( in, "/" );
             string_append( in, object_str( list_item( arg_iter ) ) );
@@ -1519,13 +1571,14 @@
             /* Found a trailing or duplicate '/'. Remove it. */
             *current = '\1';
         }
- else if ( ( end - current == 1 ) && ( *(current + 1) == '.' ) )
+ else if ( ( end - current == 1 ) && ( *( current + 1 ) == '.' ) )
         {
             /* Found '/.'. Remove them all. */
             *current = '\1';
             *(current + 1) = '\1';
         }
- else if ( ( end - current == 2 ) && ( *(current + 1) == '.' ) && ( *(current + 2) == '.' ) )
+ else if ( ( end - current == 2 ) && ( *( current + 1 ) == '.' ) &&
+ ( *( current + 2 ) == '.' ) )
         {
             /* Found '/..'. Remove them all. */
             *current = '\1';
@@ -1573,7 +1626,9 @@
      * the original path was rooted and we have an empty path we need to add
      * back the '/'.
      */
- result = object_new( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
+ result = object_new( out->size
+ ? out->value + !rooted
+ : ( rooted ? "/" : "." ) );
 
     string_free( out );
     string_free( in );
@@ -1590,7 +1645,8 @@
     module_t * module = bindmodule( list_front( module_name ) );
 
     native_rule_t * np;
- if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
+ if ( module->native_rules && (np = (native_rule_t *)hash_find(
+ module->native_rules, list_front( rule_name ) ) ) )
     {
         new_rule_body( module, np->name, np->procedure, 1 );
     }
@@ -1598,7 +1654,7 @@
     {
         backtrace_line( frame->prev );
         printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
- object_str( list_front( rule_name ) ), object_str( module->name ) );
+ object_str( list_front( rule_name ) ), object_str( module->name ) );
         backtrace( frame->prev );
         exit( 1 );
     }
@@ -1615,7 +1671,8 @@
     module_t * module = bindmodule( list_front( module_name ) );
 
     native_rule_t * np;
- if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
+ if ( module->native_rules && (np = (native_rule_t *)hash_find(
+ module->native_rules, list_front( rule_name ) ) ) )
     {
         int expected_version = atoi( object_str( list_front( version ) ) );
         if ( np->version == expected_version )
@@ -1627,29 +1684,28 @@
 
 LIST * builtin_user_module( FRAME * frame, int flags )
 {
- LIST * module_name = lol_get( frame->args, 0 );
- LISTITER iter = list_begin( module_name ), end = list_end( module_name );
+ LIST * const module_name = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( module_name );
+ LISTITER const end = list_end( module_name );
     for ( ; iter != end; iter = list_next( iter ) )
- {
- module_t * m = bindmodule( list_item( iter ) );
- m->user_module = 1;
- }
+ bindmodule( list_item( iter ) )->user_module = 1;
     return L0;
 }
 
 
 LIST * builtin_nearest_user_location( FRAME * frame, int flags )
 {
- FRAME * nearest_user_frame =
- frame->module->user_module ? frame : frame->prev_user;
+ FRAME * const nearest_user_frame = frame->module->user_module
+ ? frame
+ : frame->prev_user;
     if ( !nearest_user_frame )
         return L0;
 
     {
         LIST * result = L0;
- const char * file;
- int line;
- char buf[32];
+ char const * file;
+ int line;
+ char buf[ 32 ];
 
         get_source_line( nearest_user_frame, &file, &line );
         sprintf( buf, "%d", line );
@@ -1662,69 +1718,64 @@
 
 LIST * builtin_check_if_file( FRAME * frame, int flags )
 {
- LIST * name = lol_get( frame->args, 0 );
+ LIST * const name = lol_get( frame->args, 0 );
     return file_is_file( list_front( name ) ) == 1
         ? list_new( object_copy( constant_true ) )
- : L0 ;
+ : L0;
 }
 
 
 LIST * builtin_md5( FRAME * frame, int flags )
 {
     LIST * l = lol_get( frame->args, 0 );
- const char* s = object_str( list_front( l ) );
+ char const * s = object_str( list_front( l ) );
 
     md5_state_t state;
- md5_byte_t digest[16];
- char hex_output[16*2 + 1];
+ md5_byte_t digest[ 16 ];
+ char hex_output[ 16 * 2 + 1 ];
 
     int di;
 
     md5_init( &state );
- md5_append( &state, (const md5_byte_t *)s, strlen(s) );
+ md5_append( &state, (md5_byte_t const *)s, strlen( s ) );
     md5_finish( &state, digest );
 
- for (di = 0; di < 16; ++di)
- sprintf( hex_output + di * 2, "%02x", digest[di] );
+ for ( di = 0; di < 16; ++di )
+ sprintf( hex_output + di * 2, "%02x", digest[ di ] );
 
     return list_new( object_new( hex_output ) );
 }
 
-LIST *builtin_file_open( FRAME * frame, int flags )
+
+LIST * builtin_file_open( FRAME * frame, int flags )
 {
- const char * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
- const char * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
+ char const * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ char const * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
     int fd;
- char buffer[sizeof("4294967295")];
+ char buffer[ sizeof( "4294967295" ) ];
 
     if ( strcmp(mode, "w") == 0 )
- {
         fd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
- }
     else
- {
         fd = open( name, O_RDONLY );
- }
 
- if (fd != -1)
+ if ( fd != -1 )
     {
         sprintf( buffer, "%d", fd );
         return list_new( object_new( buffer ) );
     }
- else
- {
- return L0;
- }
+ return L0;
 }
 
-LIST *builtin_pad( FRAME * frame, int flags )
+
+LIST * builtin_pad( FRAME * frame, int flags )
 {
     OBJECT * string = list_front( lol_get( frame->args, 0 ) );
- const char * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
+ char const * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
 
     int current = strlen( object_str( string ) );
     int desired = atoi( width_s );
- if (current >= desired)
+ if ( current >= desired )
         return list_new( object_copy( string ) );
     else
     {
@@ -1734,66 +1785,58 @@
 
         strcpy( buffer, object_str( string ) );
         for ( i = current; i < desired; ++i )
- buffer[i] = ' ';
- buffer[desired] = '\0';
+ buffer[ i ] = ' ';
+ buffer[ desired ] = '\0';
         result = list_new( object_new( buffer ) );
         BJAM_FREE( buffer );
         return result;
     }
 }
 
-LIST *builtin_precious( FRAME * frame, int flags )
-{
- LIST * targets = lol_get(frame->args, 0);
-
- LISTITER iter = list_begin( targets ), end = list_end( targets );
- for ( ; iter != end; iter = list_next( iter ) )
- {
- TARGET* t = bindtarget( list_item( iter ) );
- t->flags |= T_FLAG_PRECIOUS;
- }
 
+LIST * builtin_precious( FRAME * frame, int flags )
+{
+ LIST * targets = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
+ bindtarget( list_item( iter ) )->flags |= T_FLAG_PRECIOUS;
     return L0;
 }
 
-LIST *builtin_self_path( FRAME * frame, int flags )
+
+LIST * builtin_self_path( FRAME * frame, int flags )
 {
- extern const char * saved_argv0;
+ extern char const * saved_argv0;
     char * p = executable_path( saved_argv0 );
     if ( p )
     {
- LIST* result = list_new( object_new( p ) );
+ LIST * const result = list_new( object_new( p ) );
         free( p );
         return result;
     }
- else
- {
- return L0;
- }
+ return L0;
 }
 
-LIST *builtin_makedir( FRAME * frame, int flags )
-{
- LIST * path = lol_get( frame->args, 0 );
 
- if ( file_mkdir( object_str( list_front( path ) ) ) == 0 )
- {
- LIST * result = list_new( object_copy( list_front( path ) ) );
- return result;
- }
- else
- {
- return L0;
- }
+LIST * builtin_makedir( FRAME * frame, int flags )
+{
+ LIST * const path = lol_get( frame->args, 0 );
+ return file_mkdir( object_str( list_front( path ) ) )
+ ? L0
+ : list_new( object_copy( list_front( path ) ) );
 }
 
+
 #ifdef HAVE_PYTHON
 
 LIST * builtin_python_import_rule( FRAME * frame, int flags )
 {
     static int first_time = 1;
- const char * python_module = object_str( list_front( lol_get( frame->args, 0 ) ) );
- const char * python_function = object_str( list_front( lol_get( frame->args, 1 ) ) );
+ char const * python_module = object_str( list_front( lol_get( frame->args,
+ 0 ) ) );
+ char const * python_function = object_str( list_front( lol_get( frame->args,
+ 1 ) ) );
     OBJECT * jam_module = list_front( lol_get( frame->args, 2 ) );
     OBJECT * jam_rule = list_front( lol_get( frame->args, 3 ) );
 
@@ -1859,9 +1902,10 @@
 
 }
 
-#endif
+#endif /* #ifdef HAVE_PYTHON */
+
 
-void lol_build( LOL * lol, const char * * elements )
+void lol_build( LOL * lol, char const * * elements )
 {
     LIST * l = L0;
     lol_init( lol );
@@ -1871,7 +1915,7 @@
         if ( !strcmp( *elements, ":" ) )
         {
             lol_add( lol, l );
- l = L0 ;
+ l = L0;
         }
         else
         {
@@ -1890,10 +1934,10 @@
 /*
  * Calls the bjam rule specified by name passed in 'args'. The name is looked up
  * in the context of bjam's 'python_interface' module. Returns the list of
- * string retured by the rule.
+ * strings returned by the rule.
  */
 
-PyObject* bjam_call( PyObject * self, PyObject * args )
+PyObject * bjam_call( PyObject * self, PyObject * args )
 {
     FRAME inner[ 1 ];
     LIST * result;
@@ -1944,19 +1988,21 @@
         }
     }
 
- result = evaluate_rule( rulename, inner );
+ result = evaluate_rule( bindrule( rulename, inner->module), rulename, inner );
     object_free( rulename );
 
     frame_free( inner );
 
     /* Convert the bjam list into a Python list result. */
     {
- PyObject * pyResult = PyList_New( list_length( result ) );
+ PyObject * const pyResult = PyList_New( list_length( result ) );
         int i = 0;
- LISTITER iter = list_begin( result ), end = list_end( result );
+ LISTITER iter = list_begin( result );
+ LISTITER const end = list_end( result );
         for ( ; iter != end; iter = list_next( iter ) )
         {
- PyList_SetItem( pyResult, i, PyString_FromString( object_str( list_item( iter ) ) ) );
+ PyList_SetItem( pyResult, i, PyString_FromString( object_str(
+ list_item( iter ) ) ) );
             i += 1;
         }
         list_free( result );
@@ -1966,13 +2012,13 @@
 
 
 /*
- * Accepts four arguments:
+ * Accepts four arguments:
  * - module name
  * - rule name,
- * - Python callable.
+ * - Python callable.
  * - (optional) bjam language function signature.
- * Creates a bjam rule with the specified name in the specified module, which will
- * invoke the Python callable.
+ * Creates a bjam rule with the specified name in the specified module, which
+ * will invoke the Python callable.
  */
 
 PyObject * bjam_import_rule( PyObject * self, PyObject * args )
@@ -1986,23 +2032,21 @@
     OBJECT * module_name;
     OBJECT * rule_name;
 
- if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
+ if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
                             &module, &rule, &func, &bjam_signature ) )
         return NULL;
 
     if ( !PyCallable_Check( func ) )
     {
- PyErr_SetString( PyExc_RuntimeError,
- "Non-callable object passed to bjam.import_rule" );
+ PyErr_SetString( PyExc_RuntimeError, "Non-callable object passed to "
+ "bjam.import_rule" );
         return NULL;
     }
 
     module_name = *module ? object_new( module ) : 0;
     m = bindmodule( module_name );
- if( module_name )
- {
+ if ( module_name )
         object_free( module_name );
- }
     rule_name = object_new( rule );
     new_rule_body( m, rule_name, function_python( func, bjam_signature ), 0 );
     object_free( rule_name );
@@ -2035,7 +2079,7 @@
     FUNCTION * body_func;
 
     if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
- &PyList_Type, &bindlist_python, &flags ) )
+ &PyList_Type, &bindlist_python, &flags ) )
         return NULL;
 
     n = PyList_Size( bindlist_python );
@@ -2044,11 +2088,12 @@
         PyObject * next = PyList_GetItem( bindlist_python, i );
         if ( !PyString_Check( next ) )
         {
- PyErr_SetString( PyExc_RuntimeError,
- "bind list has non-string type" );
+ PyErr_SetString( PyExc_RuntimeError, "bind list has non-string "
+ "type" );
             return NULL;
         }
- bindlist = list_push_back( bindlist, object_new( PyString_AsString( next ) ) );
+ bindlist = list_push_back( bindlist, object_new( PyString_AsString( next
+ ) ) );
     }
 
     name_str = object_new( name );
@@ -2073,7 +2118,8 @@
     PyObject * result;
     int i;
     OBJECT * varname;
- LISTITER iter, end;
+ LISTITER iter;
+ LISTITER end;
 
     if ( !PyArg_ParseTuple( args, "s", &name ) )
         return NULL;
@@ -2081,11 +2127,13 @@
     varname = object_new( name );
     value = var_get( root_module(), varname );
     object_free( varname );
- iter = list_begin( value ), end = list_end( value );
+ iter = list_begin( value );
+ end = list_end( value );
 
     result = PyList_New( list_length( value ) );
     for ( i = 0; iter != end; iter = list_next( iter ), ++i )
- PyList_SetItem( result, i, PyString_FromString( object_str( list_item( iter ) ) ) );
+ PyList_SetItem( result, i, PyString_FromString( object_str( list_item(
+ iter ) ) ) );
 
     return result;
 }
@@ -2099,10 +2147,10 @@
     for ( ; f = f->prev; )
     {
         PyObject * tuple = PyTuple_New( 4 );
- const char * file;
+ char const * file;
         int line;
         char buf[ 32 ];
- string module_name[1];
+ string module_name[ 1 ];
 
         get_source_line( f, &file, &line );
         sprintf( buf, "%d", line );
@@ -2114,8 +2162,8 @@
         }
 
         /* PyTuple_SetItem steals reference. */
- PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
- PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
+ PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
+ PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
         PyTuple_SetItem( tuple, 2, PyString_FromString( module_name->value ) );
         PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
 
@@ -2129,10 +2177,8 @@
 
 PyObject * bjam_caller( PyObject * self, PyObject * args )
 {
- const char * s = frame_before_python_call->prev->module->name ?
- object_str( frame_before_python_call->prev->module->name ) :
- "";
- return PyString_FromString( s );
+ return PyString_FromString( frame_before_python_call->prev->module->name ?
+ object_str( frame_before_python_call->prev->module->name ) : "" );
 }
 
 #endif /* #ifdef HAVE_PYTHON */
@@ -2191,9 +2237,10 @@
      * should Windows ever 'fix' this feature.
      * (03.06.2008.) (Jurko)
      */
- static FILE * windows_popen_wrapper( const char * command, const char * mode )
+ static FILE * windows_popen_wrapper( char const * command,
+ char const * mode )
     {
- int extra_command_quotes_needed = ( strchr( command, '"' ) != 0 );
+ int const extra_command_quotes_needed = !!strchr( command, '"' );
         string quoted_command;
         FILE * result;
 
@@ -2213,10 +2260,10 @@
 
         return result;
     }
-#endif
+#endif /* defined(_MSC_VER) || defined(__BORLANDC__) */
 
 
-static char * rtrim( char * s )
+static char * rtrim( char * const s )
 {
     char * p = s;
     while ( *p ) ++p;
@@ -2224,6 +2271,7 @@
     return s;
 }
 
+
 LIST * builtin_shell( FRAME * frame, int flags )
 {
     LIST * command = lol_get( frame->args, 0 );
@@ -2241,21 +2289,14 @@
     {
         int a = 1;
         LIST * arg = lol_get( frame->args, a );
- while ( !list_empty( arg ) )
+ for ( ; !list_empty( arg ); arg = lol_get( frame->args, ++a ) )
         {
- if ( strcmp( "exit-status", object_str( list_front( arg ) ) ) == 0 )
- {
+ if ( !strcmp( "exit-status", object_str( list_front( arg ) ) ) )
                 exit_status_opt = 1;
- }
- else if ( strcmp( "no-output", object_str( list_front( arg ) ) ) == 0 )
- {
+ else if ( !strcmp( "no-output", object_str( list_front( arg ) ) ) )
                 no_output_opt = 1;
- }
- else if ( strcmp("strip-eol", object_str( list_front( arg ) ) ) == 0 )
- {
+ else if ( !strcmp("strip-eol", object_str( list_front( arg ) ) ) )
                 strip_eol_opt = 1;
- }
- arg = lol_get( frame->args, ++a );
         }
     }
 
@@ -2271,13 +2312,14 @@
 
     string_new( &s );
 
- while ( ( ret = fread( buffer, sizeof( char ), sizeof( buffer ) - 1, p ) ) > 0 )
+ while ( ( ret = fread( buffer, sizeof( char ), sizeof( buffer ) - 1, p ) ) >
+ 0 )
     {
- buffer[ret] = 0;
+ buffer[ ret ] = 0;
         if ( !no_output_opt )
         {
             if ( strip_eol_opt )
- rtrim(buffer);
+ rtrim( buffer );
             string_append( &s, buffer );
         }
     }
@@ -2291,8 +2333,8 @@
     /* The command exit result next. */
     if ( exit_status_opt )
     {
- if ( WIFEXITED(exit_status) )
- exit_status = WEXITSTATUS(exit_status);
+ if ( WIFEXITED( exit_status ) )
+ exit_status = WEXITSTATUS( exit_status );
         else
             exit_status = -1;
         sprintf( buffer, "%d", exit_status );
@@ -2309,4 +2351,4 @@
     return L0;
 }
 
-#endif /* #ifdef HAVE_POPEN */
+#endif /* #ifdef HAVE_POPEN */

Modified: branches/release/tools/build/v2/engine/builtins.h
==============================================================================
--- branches/release/tools/build/v2/engine/builtins.h (original)
+++ branches/release/tools/build/v2/engine/builtins.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -21,6 +21,8 @@
 void init_sequence();
 void init_order();
 
+void property_set_done();
+
 LIST *builtin_calc( FRAME * frame, int flags );
 LIST *builtin_depends( FRAME * frame, int flags );
 LIST *builtin_rebuilds( FRAME * frame, int flags );

Modified: branches/release/tools/build/v2/engine/bump_version.py
==============================================================================
--- branches/release/tools/build/v2/engine/bump_version.py (original)
+++ branches/release/tools/build/v2/engine/bump_version.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,12 +1,15 @@
 #!/usr/bin/python
 
-# This script is used to bump version of bjam. It takes a single argument, e.g
+# This script is used to bump the bjam version. It takes a single argument, e.g
 #
 # ./bump_version.py 3.1.9
 #
-# and updates all necessary files. For the time being, it's assumes presense
-# of 'perl' executable and Debian-specific 'dch' executable.
+# and updates all the necessary files.
 #
+# Copyright 2006 Rene Rivera.
+# Copyright 2005-2006 Vladimir Prus.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 
 import os
@@ -15,66 +18,81 @@
 import string
 import sys
 
-srcdir = os.path.abspath(os.path.dirname(__file__ ))
-docdir = os.path.abspath(os.path.join(srcdir,"..","doc"))
+srcdir = os.path.abspath(os.path.dirname(__file__))
+docdir = os.path.abspath(os.path.join(srcdir, "..", "doc"))
 
-def edit(file,replacements):
- print " '%s'..." %(file)
- text = open(file,'r').read()
- while len(replacements) > 0:
- #~ print " '%s' ==> '%s'" % (replacements[0],replacements[1])
- text = re.compile(replacements[0],re.M).subn(replacements[1],text)[0]
- replacements = replacements[2:]
- #~ print text
- open(file,'w').write(text)
-
-def make_edits(version):
- edit(os.path.join(srcdir,"boost-jam.spec"), [
- '^Version:.*$','Version: %s' % string.join(version, "."),
- ])
-
- edit(os.path.join(srcdir,"build.jam"), [
- '^_VERSION_ = .* ;$','_VERSION_ = %s %s %s ;' % (version[0], version[1], version[2]),
- ])
-
- edit(os.path.join(docdir,"bjam.qbk"), [
- '\[version.*\]','[version: %s]' % string.join(version, '.'),
- '\[def :version:.*\]','[def :version: %s]' % string.join(version, '.'),
- ])
-
- edit(os.path.join(srcdir,"patchlevel.h"), [
- '^#define VERSION_MAJOR .*$',
- '#define VERSION_MAJOR %s' % (version[0]),
- '^#define VERSION_MINOR .*$',
- '#define VERSION_MINOR %s' % (version[1]),
- '^#define VERSION_PATCH .*$',
- '#define VERSION_PATCH %s' % (version[2]),
- '^#define VERSION_MAJOR_SYM .*$',
- '#define VERSION_MAJOR_SYM "0%s"' % (version[0]),
- '^#define VERSION_MINOR_SYM .*$',
- '#define VERSION_MINOR_SYM "%s"' % (version[1]),
- '^#define VERSION_PATCH_SYM .*$',
- '#define VERSION_PATCH_SYM "%s"' % (version[2]),
- '^#define VERSION .*$',
- '#define VERSION "%s"' % string.join(version, '.'),
- '^#define JAMVERSYM .*$',
- '#define JAMVERSYM "JAMVERSION=%s.%s"' % (version[0],version[1]),
- ])
 
-def main():
+def edit(file, *replacements):
+ print(" '%s'..." % file)
+ f = open(file, 'r')
+ text = f.read()
+ f.close()
+ for (source, target) in replacements:
+ text, n = re.compile(source, re.MULTILINE).subn(target, text)
+ assert n > 0
+ f = open(file, 'w')
+ f.write(text)
+ f.close()
+
+
+def make_edits(ver):
+ ver03 = (list(ver) + [0] * 3)[0:3]
+ ver02 = ver03[0:2]
+
+ join = lambda v, s : s.join(str(x) for x in v)
+ dotJoin = lambda v : join(v, ".")
+
+ print("Setting version to %s" % str(ver03))
+
+ edit(os.path.join(srcdir, "boost-jam.spec"),
+ ('^(Version:) .*$', '\\1 %s' % dotJoin(ver03)))
+
+ edit(os.path.join(srcdir, "build.jam"),
+ ('^(_VERSION_ =).* ;$', '\\1 %s ;' % join(ver03, " ")))
+
+ edit(os.path.join(docdir, "bjam.qbk"),
+ ('(\[version).*(\])', '\\1: %s\\2' % dotJoin(ver03)),
+ ('(\[def :version:).*(\])', '\\1 %s\\2' % dotJoin(ver03)))
+
+ edit(os.path.join(srcdir, "patchlevel.h"),
+ ('^(#define VERSION_MAJOR) .*$', '\\1 %s' % ver03[0]),
+ ('^(#define VERSION_MINOR) .*$', '\\1 %s' % ver03[1]),
+ ('^(#define VERSION_PATCH) .*$', '\\1 %s' % ver03[2]),
+ ('^(#define VERSION_MAJOR_SYM) .*$', '\\1 "%02d"' % ver03[0]),
+ ('^(#define VERSION_MINOR_SYM) .*$', '\\1 "%02d"' % ver03[1]),
+ ('^(#define VERSION_PATCH_SYM) .*$', '\\1 "%02d"' % ver03[2]),
+ ('^(#define VERSION) .*$', '\\1 "%s"' % dotJoin(ver)),
+ ('^(#define JAMVERSYM) .*$', '\\1 "JAMVERSION=%s"' % dotJoin(ver02)))
+
 
+def main():
     if len(sys.argv) < 2:
- print "Expect new version as argument"
+ print("Expect new version as argument.")
+ sys.exit(1)
+ if len(sys.argv) > 3:
+ print("Too many arguments.")
+ sys.exit(1)
+
+ version = sys.argv[1].split(".")
+ if len(version) > 3:
+ print("Expect version argument in the format: <MAJOR>.<MINOR>.<PATCH>")
         sys.exit(1)
 
- version = string.split(sys.argv[1], ".")
- print "Setting version to", version
+ try:
+ version = list(int(x) for x in version)
+ except ValueError:
+ print("Version values must be valid integers.")
+ sys.exit(1)
+
+ while version and version[-1] == 0:
+ version.pop()
+
+ if not version:
+ print("At least one of the version values must be positive.")
+ sys.exit()
+
     make_edits(version)
 
+
 if __name__ == '__main__':
     main()
-
-#~ Copyright 2006 Rene Rivera.
-#~ Copyright 2005-2006 Vladimir Prus.
-#~ 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)

Modified: branches/release/tools/build/v2/engine/class.c
==============================================================================
--- branches/release/tools/build/v2/engine/class.c (original)
+++ branches/release/tools/build/v2/engine/class.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,15 +1,23 @@
-/* Copyright Vladimir Prus 2003. 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) */
+/*
+ * Copyright Vladimir Prus 2003.
+ * 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)
+ */
 
 #include "class.h"
-#include "strings.h"
-#include "variable.h"
+
+#include "constants.h"
 #include "frames.h"
-#include "rules.h"
+#include "hash.h"
+#include "lists.h"
 #include "object.h"
+#include "rules.h"
+#include "strings.h"
+#include "variable.h"
 
-#include "hash.h"
+#include <stdio.h>
+#include <stdlib.h>
 
 
 static struct hash * classes = 0;
@@ -17,12 +25,14 @@
 
 static void check_defined( LIST * class_names )
 {
- LISTITER iter = list_begin( class_names ), end = list_end( class_names );
+ LISTITER iter = list_begin( class_names );
+ LISTITER const end = list_end( class_names );
     for ( ; iter != end; iter = list_next( iter ) )
     {
         if ( !hash_find( classes, list_item( iter ) ) )
         {
- printf( "Class %s is not defined\n", object_str( list_item( iter ) ) );
+ printf( "Class %s is not defined\n", object_str( list_item( iter ) )
+ );
             abort();
         }
     }
@@ -59,15 +69,15 @@
     RULE * ir1;
     RULE * ir2;
     struct import_base_data * d = (struct import_base_data *)d_;
- string qualified_name[ 1 ];
     OBJECT * qname;
 
- string_new ( qualified_name );
+ string qualified_name[ 1 ];
+ string_new ( qualified_name );
     string_append ( qualified_name, object_str( d->base_name ) );
- string_push_back( qualified_name, '.' );
- string_append ( qualified_name, object_str( r->name ) );
-
+ string_push_back( qualified_name, '.' );
+ string_append ( qualified_name, object_str( r->name ) );
     qname = object_new( qualified_name->value );
+ string_free( qualified_name );
 
     ir1 = import_rule( r, d->class_module, r->name );
     ir2 = import_rule( r, d->class_module, qname );
@@ -84,8 +94,6 @@
         rule_localize( ir1, d->class_module );
         rule_localize( ir2, d->class_module );
     }
-
- string_free( qualified_name );
 }
 
 
@@ -122,7 +130,6 @@
     module_t * class_module = 0;
     module_t * outer_module = frame->module;
     int found;
- LISTITER iter, end;
 
     if ( !classes )
         classes = hashinit( sizeof( OBJECT * ), "classes" );
@@ -134,31 +141,48 @@
     }
     else
     {
- printf( "Class %s already defined\n", object_str( list_front( xname ) ) );
+ printf( "Class %s already defined\n", object_str( list_front( xname ) )
+ );
         abort();
     }
     check_defined( bases );
 
     class_module = bindmodule( name );
 
+ {
+ /*
+ Initialize variables that Boost.Build inserts in every object.
+ We want to avoid creating the object's hash if it isn't needed.
+ */
+ int num = class_module->num_fixed_variables;
+ module_add_fixed_var( class_module, constant_name, &num );
+ module_add_fixed_var( class_module, constant_class, &num );
+ module_set_fixed_variables( class_module, num );
+ }
+
     var_set( class_module, constant_name, xname, VAR_SET );
     var_set( class_module, constant_bases, bases, VAR_SET );
 
- iter = list_begin( bases ), end = list_end( bases );
- for ( ; iter != end; iter = list_next( iter ) )
- import_base_rules( class_module, list_item( iter ) );
+ {
+ LISTITER iter = list_begin( bases );
+ LISTITER const end = list_end( bases );
+ for ( ; iter != end; iter = list_next( iter ) )
+ import_base_rules( class_module, list_item( iter ) );
+ }
 
     return name;
 }
 
+
 static void free_class( void * xclass, void * data )
 {
     object_free( *(OBJECT * *)xclass );
 }
 
+
 void class_done( void )
 {
- if( classes )
+ if ( classes )
     {
         hashenumerate( classes, free_class, (void *)0 );
         hashdone( classes );

Modified: branches/release/tools/build/v2/engine/command.c
==============================================================================
--- branches/release/tools/build/v2/engine/command.c (original)
+++ branches/release/tools/build/v2/engine/command.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -15,33 +15,28 @@
  */
 
 #include "jam.h"
+#include "command.h"
 
 #include "lists.h"
-#include "parse.h"
-#include "variable.h"
 #include "rules.h"
 
-#include "command.h"
-#include <limits.h>
-#include <string.h>
+#include <assert.h>
 
 
 /*
- * cmd_new() - return a new CMD or 0 if too many args
+ * cmd_new() - return a new CMD.
  */
 
 CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
 {
     CMD * cmd = (CMD *)BJAM_MALLOC( sizeof( CMD ) );
- LISTITER iter = list_begin( shell ), end = list_end( shell );
- /* Lift line-length limitation entirely when JAMSHELL is just "%". */
- int no_limit = ( iter != end && !strcmp( object_str( list_item( iter ) ), "%") && list_next( iter ) == end );
- int max_line = MAXLINE;
- FRAME frame[1];
+ FRAME frame[ 1 ];
 
+ assert( cmd );
     cmd->rule = rule;
     cmd->shell = shell;
     cmd->next = 0;
+ cmd->noop = 0;
 
     lol_init( &cmd->args );
     lol_add( &cmd->args, targets );
@@ -53,30 +48,10 @@
     lol_init( frame->args );
     lol_add( frame->args, list_copy( targets ) );
     lol_add( frame->args, list_copy( sources ) );
- function_run_actions( rule->actions->command, frame, stack_global(), cmd->buf );
+ function_run_actions( rule->actions->command, frame, stack_global(),
+ cmd->buf );
     frame_free( frame );
 
- if ( !no_limit )
- {
- /* Bail if the result will not fit in MAXLINE. */
- char * s = cmd->buf->value;
- while ( *s )
- {
- size_t l = strcspn( s, "\n" );
-
- if ( l > MAXLINE )
- {
- /* We do not free targets/sources/shell if bailing. */
- cmd_free( cmd );
- return 0;
- }
-
- s += l;
- if ( *s )
- ++s;
- }
- }
-
     return cmd;
 }
 
@@ -92,3 +67,18 @@
     string_free( cmd->buf );
     BJAM_FREE( (void *)cmd );
 }
+
+
+/*
+ * cmd_release_targets_and_shell()
+ *
+ * Makes the CMD release its hold on its targets & shell lists and forget
+ * about them. Useful in case caller still has references to those lists and
+ * wants to reuse them after freeing the CMD object.
+ */
+
+void cmd_release_targets_and_shell( CMD * cmd )
+{
+ cmd->args.list[ 0 ] = L0; /* targets */
+ cmd->shell = L0; /* shell */
+}

Modified: branches/release/tools/build/v2/engine/command.h
==============================================================================
--- branches/release/tools/build/v2/engine/command.h (original)
+++ branches/release/tools/build/v2/engine/command.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -29,6 +29,7 @@
  * cmd_new() - return a new CMD or 0 if too many args.
  * cmd_free() - delete CMD and its parts.
  * cmd_next() - walk the CMD chain.
+ * cmd_release_targets_and_shell() - CMD forgets about its targets & shell.
  */
 
 
@@ -43,28 +44,30 @@
 #include "rules.h"
 #include "strings.h"
 
-typedef struct _cmd CMD;
 
+typedef struct _cmd CMD;
 struct _cmd
 {
     CMD * next;
- CMD * tail; /* valid on in head */
- RULE * rule; /* rule->actions contains shell script */
- LIST * shell; /* $(SHELL) value */
- LOL args; /* LISTs for $(<), $(>) */
- string buf[1]; /* actual commands */
+ RULE * rule; /* rule->actions contains shell script */
+ LIST * shell; /* $(JAMSHELL) value */
+ LOL args; /* LISTs for $(<), $(>) */
+ string buf[ 1 ]; /* actual commands */
+ int noop; /* no-op commands should be faked instead of executed */
 };
 
 CMD * cmd_new
 (
     RULE * rule, /* rule (referenced) */
- LIST * targets, /* $(<) (freed) */
- LIST * sources, /* $(>) (freed) */
- LIST * shell /* $(SHELL) (freed) */
+ LIST * targets, /* $(<) (ownership transferred) */
+ LIST * sources, /* $(>) (ownership transferred) */
+ LIST * shell /* $(JAMSHELL) (ownership transferred) */
 );
 
+void cmd_release_targets_and_shell( CMD * );
+
 void cmd_free( CMD * );
 
-#define cmd_next( c ) ( ( c )->next )
+#define cmd_next( c ) ((c)->next)
 
 #endif

Modified: branches/release/tools/build/v2/engine/compile.c
==============================================================================
--- branches/release/tools/build/v2/engine/compile.c (original)
+++ branches/release/tools/build/v2/engine/compile.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,146 +10,72 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-# include "jam.h"
-
-# include "lists.h"
-# include "parse.h"
-# include "compile.h"
-# include "variable.h"
-# include "rules.h"
-# include "object.h"
-# include "make.h"
-# include "search.h"
-# include "hdrmacro.h"
-# include "hash.h"
-# include "modules.h"
-# include "strings.h"
-# include "builtins.h"
-# include "class.h"
-# include "constants.h"
-
-# include <assert.h>
-# include <string.h>
-# include <stdarg.h>
-
 /*
  * compile.c - compile parsed jam statements
  *
  * External routines:
- *
- * compile_append() - append list results of two statements
- * compile_eval() - evaluate if to determine which leg to compile
- * compile_foreach() - compile the "for x in y" statement
- * compile_if() - compile 'if' rule
- * compile_while() - compile 'while' rule
- * compile_include() - support for 'include' - call include() on file
- * compile_list() - expand and return a list
- * compile_local() - declare (and set) local variables
- * compile_null() - do nothing -- a stub for parsing
- * compile_on() - run rule under influence of on-target variables
- * compile_rule() - compile a single user defined rule
- * compile_rules() - compile a chain of rules
- * compile_set() - compile the "set variable" statement
- * compile_setcomp() - support for `rule` - save parse tree
- * compile_setexec() - support for `actions` - save execution string
- * compile_settings() - compile the "on =" (set variable on exec) statement
- * compile_switch() - compile 'switch' rule
- *
- * Internal routines:
- *
- * debug_compile() - printf with indent to show rule expansion.
  * evaluate_rule() - execute a rule invocation
  *
- * builtin_depends() - DEPENDS/INCLUDES rule
- * builtin_echo() - ECHO rule
- * builtin_exit() - EXIT rule
- * builtin_flags() - NOCARE, NOTFILE, TEMPORARY rule
- *
- * 02/03/94 (seiwald) - Changed trace output to read "setting" instead of
- * the awkward sounding "settings".
- * 04/12/94 (seiwald) - Combined build_depends() with build_includes().
- * 04/12/94 (seiwald) - actionlist() now just appends a single action.
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 05/13/94 (seiwald) - include files are now bound as targets, and thus
- * can make use of $(SEARCH)
- * 06/01/94 (seiwald) - new 'actions existing' does existing sources
- * 08/23/94 (seiwald) - Support for '+=' (append to variable)
- * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
- * 01/22/95 (seiwald) - Exit rule.
- * 02/02/95 (seiwald) - Always rule; LEAVES rule.
- * 02/14/95 (seiwald) - NoUpdate rule.
- * 09/11/00 (seiwald) - new evaluate_rule() for headers().
- * 09/11/00 (seiwald) - compile_xxx() now return LIST *.
- * New compile_append() and compile_list() in
- * support of building lists here, rather than
- * in jamgram.yy.
- * 01/10/00 (seiwald) - built-ins split out to builtin.c.
+ * Internal routines:
+ * debug_compile() - printf with indent to show rule expansion
  */
 
-static void debug_compile( int which, const char * s, FRAME * frame );
-int glob( const char * s, const char * c );
-/* Internal functions from builtins.c */
-void backtrace( FRAME * frame );
-void backtrace_line( FRAME * frame );
-void print_source_line( FRAME * frame );
-
-struct frame * frame_before_python_call;
+#include "jam.h"
+#include "compile.h"
 
-static OBJECT * module_scope;
+#include "builtins.h"
+#include "class.h"
+#include "constants.h"
+#include "hash.h"
+#include "hdrmacro.h"
+#include "make.h"
+#include "modules.h"
+#include "parse.h"
+#include "rules.h"
+#include "search.h"
+#include "strings.h"
+#include "variable.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
 
-void frame_init( FRAME* frame )
-{
- frame->prev = 0;
- frame->prev_user = 0;
- lol_init(frame->args);
- frame->module = root_module();
- frame->rulename = "module scope";
- frame->file = 0;
- frame->line = -1;
-}
 
+static void debug_compile( int which, char const * s, FRAME * );
 
-void frame_free( FRAME* frame )
-{
- lol_free( frame->args );
-}
+/* Internal functions from builtins.c */
+void backtrace( FRAME * );
+void backtrace_line( FRAME * );
+void print_source_line( FRAME * );
+void unknown_rule( FRAME *, char const * key, module_t *, OBJECT * rule_name );
 
 
 /*
- * evaluate_rule() - execute a rule invocation.
+ * evaluate_rule() - execute a rule invocation
  */
 
-LIST *
-evaluate_rule(
- OBJECT * rulename,
- FRAME * frame )
+LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * frame )
 {
     LIST * result = L0;
- RULE * rule;
- profile_frame prof[1];
+ profile_frame prof[ 1 ];
     module_t * prev_module = frame->module;
 
- rule = bindrule( rulename, frame->module );
-
     if ( DEBUG_COMPILE )
     {
         /* Try hard to indicate in which module the rule is going to execute. */
- if ( rule->module != frame->module
- && rule->procedure != 0 && !object_equal( rulename, function_rulename( rule->procedure ) ) )
+ char buf[ 256 ] = "";
+ if ( rule->module->name )
         {
- char buf[256] = "";
- if ( rule->module->name )
+ strncat( buf, object_str( rule->module->name ), sizeof( buf ) -
+ 1 );
+ strncat( buf, ".", sizeof( buf ) - 1 );
+ if ( strncmp( buf, object_str( rule->name ), strlen( buf ) ) == 0 )
             {
- strncat( buf, object_str( rule->module->name ), sizeof( buf ) - 1 );
- strncat( buf, ".", sizeof( buf ) - 1 );
+ buf[ 0 ] = 0;
             }
- strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 );
- debug_compile( 1, buf, frame );
- }
- else
- {
- debug_compile( 1, object_str( rulename ), frame );
         }
+ strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 );
+ debug_compile( 1, buf, frame );
 
         lol_print( frame->args );
         printf( "\n" );
@@ -172,19 +98,7 @@
 
     /* Check traditional targets $(<) and sources $(>). */
     if ( !rule->actions && !rule->procedure )
- {
- backtrace_line( frame->prev );
- if ( frame->module->name )
- {
- printf( "rule %s unknown in module %s\n", object_str( rule->name ), object_str( frame->module->name ) );
- }
- else
- {
- printf( "rule %s unknown in module \n", object_str( rule->name ) );
- }
- backtrace( frame->prev );
- exit( 1 );
- }
+ unknown_rule( frame, NULL, frame->module, rule->name );
 
     /* If this rule will be executed for updating the targets then construct the
      * action for make().
@@ -192,10 +106,9 @@
     if ( rule->actions )
     {
         TARGETS * t;
- ACTION * action;
 
         /* The action is associated with this instance of this rule. */
- action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) );
+ ACTION * const action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) );
         memset( (char *)action, '\0', sizeof( *action ) );
 
         action->rule = rule;
@@ -205,11 +118,12 @@
 
         /* If we have a group of targets all being built using the same action
          * then we must not allow any of them to be used as sources unless they
- * had all already been built in the first place or their joined action
- * has had a chance to finish its work and build all of them anew.
+ * are all up to date and their action does not need to be run or their
+ * action has had a chance to finish its work and build all of them
+ * anew.
          *
          * Without this it might be possible, in case of a multi-process build,
- * for their action, triggered by buiding one of the targets, to still
+ * for their action, triggered to building one of the targets, to still
          * be running when another target in the group reports as done in order
          * to avoid triggering the same action again and gets used prematurely.
          *
@@ -223,7 +137,7 @@
          * dependency' issue.
          *
          * TODO: Although the current implementation solves the problem of one
- * of the targets getting used before its action completes its work it
+ * of the targets getting used before its action completes its work, it
          * also forces the action to run whenever any of the targets in the
          * group is not up to date even though some of them might not actually
          * be used by the targets being built. We should see how we can
@@ -231,13 +145,24 @@
          * action if possible and not rebuild targets not actually depending on
          * targets that are not up to date.
          *
- * TODO: Using the 'include' feature might have side-effects due to
- * interaction with the actual 'inclusion scanning' system. This should
- * be checked.
+ * TODO: Current solution using fake INCLUDES relations may cause
+ * actions to be run when the affected targets are built by multiple
+ * actions. E.g. if we have the following actions registered in the
+ * order specified:
+ * (I) builds targets A & B
+ * (II) builds target B
+ * and we want to build a target depending on target A, then both
+ * actions (I) & (II) will be run, even though the second one does not
+ * have any direct relationship to target A. Consider whether this is
+ * desired behaviour or not. It could be that Boost Build should (or
+ * possibly already does) run all actions registered for a given target
+ * if any of them needs to be run in which case our INCLUDES relations
+ * are not actually causing any actions to be run that would not have
+ * been run without them.
          */
         if ( action->targets )
         {
- TARGET * t0 = action->targets->target;
+ TARGET * const t0 = action->targets->target;
             for ( t = action->targets->next; t; t = t->next )
             {
                 target_include( t->target, t0 );
@@ -253,13 +178,12 @@
     }
 
     /* Now recursively compile any parse tree associated with this rule.
- * function_refer()/function_free() call pair added to ensure rule not freed
- * during use.
+ * function_refer()/function_free() call pair added to ensure the rule does
+ * not get freed while in use.
      */
     if ( rule->procedure )
     {
- FUNCTION * function = rule->procedure;
-
+ FUNCTION * const function = rule->procedure;
         function_refer( function );
         result = function_run( function, frame, stack_global() );
         function_free( function );
@@ -269,7 +193,7 @@
         profile_exit( prof );
 
     if ( DEBUG_COMPILE )
- debug_compile( -1, 0, frame);
+ debug_compile( -1, 0, frame );
 
     return result;
 }
@@ -289,24 +213,25 @@
     va_list va;
     LIST * result;
 
- FRAME inner[1];
+ FRAME inner[ 1 ];
     frame_init( inner );
     inner->prev = caller_frame;
- inner->prev_user = caller_frame->module->user_module ?
- caller_frame : caller_frame->prev_user;
+ inner->prev_user = caller_frame->module->user_module
+ ? caller_frame
+ : caller_frame->prev_user;
     inner->module = caller_frame->module;
 
     va_start( va, caller_frame );
     for ( ; ; )
     {
- LIST * l = va_arg( va, LIST* );
+ LIST * const l = va_arg( va, LIST * );
         if ( !l )
             break;
         lol_add( inner->args, l );
     }
     va_end( va );
 
- result = evaluate_rule( rulename, inner );
+ result = evaluate_rule( bindrule( rulename, inner->module ), rulename, inner );
 
     frame_free( inner );
 
@@ -314,15 +239,14 @@
 }
 
 
-
 /*
- * debug_compile() - printf with indent to show rule expansion.
+ * debug_compile() - printf with indent to show rule expansion
  */
 
-static void debug_compile( int which, const char * s, FRAME * frame )
+static void debug_compile( int which, char const * s, FRAME * frame )
 {
     static int level = 0;
- static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
+ static char indent[ 36 ] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
 
     if ( which >= 0 )
     {

Modified: branches/release/tools/build/v2/engine/compile.h
==============================================================================
--- branches/release/tools/build/v2/engine/compile.h (original)
+++ branches/release/tools/build/v2/engine/compile.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,54 +10,50 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-#ifndef COMPILE_DWA20011022_H
-# define COMPILE_DWA20011022_H
-
-# include "frames.h"
-# include "parse.h"
-# include "regexp.h"
-# include "object.h"
-
 /*
  * compile.h - compile parsed jam statements
  */
 
-void compile_builtins();
+#ifndef COMPILE_DWA20011022_H
+#define COMPILE_DWA20011022_H
+
+#include "frames.h"
+#include "lists.h"
+#include "object.h"
+#include "rules.h"
 
-LIST *evaluate_rule( OBJECT * rulename, FRAME * frame );
-LIST *call_rule( OBJECT * rulename, FRAME * caller_frame, ...);
+void compile_builtins();
 
-regexp* regex_compile( OBJECT * pattern );
+LIST * evaluate_rule( RULE * rule, OBJECT * rulename, FRAME * );
+LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... );
 
 /* Flags for compile_set(), etc */
 
-# define ASSIGN_SET 0x00 /* = assign variable */
-# define ASSIGN_APPEND 0x01 /* += append variable */
-# define ASSIGN_DEFAULT 0x02 /* set only if unset */
+#define ASSIGN_SET 0x00 /* = assign variable */
+#define ASSIGN_APPEND 0x01 /* += append variable */
+#define ASSIGN_DEFAULT 0x02 /* set only if unset */
 
 /* Flags for compile_setexec() */
 
-# define EXEC_UPDATED 0x01 /* executes updated */
-# define EXEC_TOGETHER 0x02 /* executes together */
-# define EXEC_IGNORE 0x04 /* executes ignore */
-# define EXEC_QUIETLY 0x08 /* executes quietly */
-# define EXEC_PIECEMEAL 0x10 /* executes piecemeal */
-# define EXEC_EXISTING 0x20 /* executes existing */
+#define EXEC_UPDATED 0x01 /* executes updated */
+#define EXEC_TOGETHER 0x02 /* executes together */
+#define EXEC_IGNORE 0x04 /* executes ignore */
+#define EXEC_QUIETLY 0x08 /* executes quietly */
+#define EXEC_PIECEMEAL 0x10 /* executes piecemeal */
+#define EXEC_EXISTING 0x20 /* executes existing */
 
 /* Conditions for compile_if() */
 
-# define EXPR_NOT 0 /* ! cond */
-# define EXPR_AND 1 /* cond && cond */
-# define EXPR_OR 2 /* cond || cond */
-
-# define EXPR_EXISTS 3 /* arg */
-# define EXPR_EQUALS 4 /* arg = arg */
-# define EXPR_NOTEQ 5 /* arg != arg */
-# define EXPR_LESS 6 /* arg < arg */
-# define EXPR_LESSEQ 7 /* arg <= arg */
-# define EXPR_MORE 8 /* arg > arg */
-# define EXPR_MOREEQ 9 /* arg >= arg */
-# define EXPR_IN 10 /* arg in arg */
+#define EXPR_NOT 0 /* ! cond */
+#define EXPR_AND 1 /* cond && cond */
+#define EXPR_OR 2 /* cond || cond */
+#define EXPR_EXISTS 3 /* arg */
+#define EXPR_EQUALS 4 /* arg = arg */
+#define EXPR_NOTEQ 5 /* arg != arg */
+#define EXPR_LESS 6 /* arg < arg */
+#define EXPR_LESSEQ 7 /* arg <= arg */
+#define EXPR_MORE 8 /* arg > arg */
+#define EXPR_MOREEQ 9 /* arg >= arg */
+#define EXPR_IN 10 /* arg in arg */
 
 #endif
-

Modified: branches/release/tools/build/v2/engine/constants.c
==============================================================================
--- branches/release/tools/build/v2/engine/constants.c (original)
+++ branches/release/tools/build/v2/engine/constants.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,9 +4,6 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-# include "constants.h"
-# include "object.h"
-
 /*
  * constants.c - constant objects
  *
@@ -17,67 +14,70 @@
  *
  */
 
+#include "constants.h"
+
+
 void constants_init( void )
 {
- constant_empty = object_new( "" );
- constant_dot = object_new( "." );
- constant_percent = object_new( "%" );
- constant_plus = object_new( "+" );
- constant_star = object_new( "*" );
- constant_question_mark = object_new( "?" );
- constant_ok = object_new( "ok" );
- constant_true = object_new( "true" );
- constant_name = object_new( "__name__" );
- constant_bases = object_new( "__bases__" );
- constant_typecheck = object_new( ".typecheck" );
- constant_builtin = object_new( "(builtin)" );
- constant_HCACHEFILE = object_new( "HCACHEFILE" );
- constant_HCACHEMAXAGE = object_new( "HCACHEMAXAGE" );
- constant_HDRSCAN = object_new( "HDRSCAN" );
- constant_HDRRULE = object_new( "HDRRULE" );
- constant_BINDRULE = object_new( "BINDRULE" );
- constant_LOCATE = object_new( "LOCATE" );
- constant_SEARCH = object_new( "SEARCH" );
- constant_JAM_SEMAPHORE = object_new( "JAM_SEMAPHORE" );
- constant_TIMING_RULE = object_new( "__TIMING_RULE__" );
- constant_ACTION_RULE = object_new( "__ACTION_RULE__" );
- constant_JAMSHELL = object_new( "JAMSHELL" );
- constant_TMPDIR = object_new( "TMPDIR" );
- constant_TMPNAME = object_new( "TMPNAME" );
- constant_TMPFILE = object_new( "TMPFILE" );
- constant_STDOUT = object_new( "STDOUT" );
- constant_STDERR = object_new( "STDERR" );
- constant_JAMDATE = object_new( "JAMDATE" );
- constant_JAM_VERSION = object_new( "JAM_VERSION" );
- constant_JAMUNAME = object_new( "JAMUNAME" );
- constant_ENVIRON = object_new( ".ENVIRON" );
- constant_ARGV = object_new( "ARGV" );
- constant_all = object_new( "all" );
- constant_PARALLELISM = object_new( "PARALLELISM" );
- constant_KEEP_GOING = object_new( "KEEP_GOING" );
- constant_other = object_new( "[OTHER]" );
- constant_total = object_new( "[TOTAL]" );
- constant_FILE_DIRSCAN = object_new( "FILE_DIRSCAN" );
- constant_MAIN = object_new( "MAIN" );
- constant_MAIN_MAKE = object_new( "MAIN_MAKE" );
- constant_MAKE_MAKE0 = object_new( "MAKE_MAKE0" );
- constant_MAKE_MAKE1 = object_new( "MAKE_MAKE1" );
- constant_MAKE_MAKE0SORT = object_new( "MAKE_MAKE0SORT" );
- constant_BINDMODULE = object_new( "BINDMODULE" );
- constant_IMPORT_MODULE = object_new( "IMPORT_MODULE" );
- constant_BUILTIN_GLOB_BACK = object_new( "BUILTIN_GLOB_BACK" );
- constant_timestamp = object_new( "timestamp" );
- constant_python = object_new("__python__");
- constant_python_interface = object_new( "python_interface" );
- constant_extra_pythonpath = object_new( "EXTRA_PYTHONPATH" );
- constant_MAIN_PYTHON = object_new( "MAIN_PYTHON" );
+ constant_empty = object_new( "" );
+ constant_dot = object_new( "." );
+ constant_plus = object_new( "+" );
+ constant_star = object_new( "*" );
+ constant_question_mark = object_new( "?" );
+ constant_ok = object_new( "ok" );
+ constant_true = object_new( "true" );
+ constant_name = object_new( "__name__" );
+ constant_bases = object_new( "__bases__" );
+ constant_class = object_new( "__class__" );
+ constant_typecheck = object_new( ".typecheck" );
+ constant_builtin = object_new( "(builtin)" );
+ constant_HCACHEFILE = object_new( "HCACHEFILE" );
+ constant_HCACHEMAXAGE = object_new( "HCACHEMAXAGE" );
+ constant_HDRSCAN = object_new( "HDRSCAN" );
+ constant_HDRRULE = object_new( "HDRRULE" );
+ constant_BINDRULE = object_new( "BINDRULE" );
+ constant_LOCATE = object_new( "LOCATE" );
+ constant_SEARCH = object_new( "SEARCH" );
+ constant_JAM_SEMAPHORE = object_new( "JAM_SEMAPHORE" );
+ constant_TIMING_RULE = object_new( "__TIMING_RULE__" );
+ constant_ACTION_RULE = object_new( "__ACTION_RULE__" );
+ constant_JAMSHELL = object_new( "JAMSHELL" );
+ constant_TMPDIR = object_new( "TMPDIR" );
+ constant_TMPNAME = object_new( "TMPNAME" );
+ constant_TMPFILE = object_new( "TMPFILE" );
+ constant_STDOUT = object_new( "STDOUT" );
+ constant_STDERR = object_new( "STDERR" );
+ constant_JAMDATE = object_new( "JAMDATE" );
+ constant_JAM_TIMESTAMP_RESOLUTION = object_new( "JAM_TIMESTAMP_RESOLUTION" );
+ constant_JAM_VERSION = object_new( "JAM_VERSION" );
+ constant_JAMUNAME = object_new( "JAMUNAME" );
+ constant_ENVIRON = object_new( ".ENVIRON" );
+ constant_ARGV = object_new( "ARGV" );
+ constant_all = object_new( "all" );
+ constant_PARALLELISM = object_new( "PARALLELISM" );
+ constant_KEEP_GOING = object_new( "KEEP_GOING" );
+ constant_other = object_new( "[OTHER]" );
+ constant_total = object_new( "[TOTAL]" );
+ constant_FILE_DIRSCAN = object_new( "FILE_DIRSCAN" );
+ constant_MAIN = object_new( "MAIN" );
+ constant_MAIN_MAKE = object_new( "MAIN_MAKE" );
+ constant_MAKE_MAKE0 = object_new( "MAKE_MAKE0" );
+ constant_MAKE_MAKE1 = object_new( "MAKE_MAKE1" );
+ constant_MAKE_MAKE0SORT = object_new( "MAKE_MAKE0SORT" );
+ constant_BINDMODULE = object_new( "BINDMODULE" );
+ constant_IMPORT_MODULE = object_new( "IMPORT_MODULE" );
+ constant_BUILTIN_GLOB_BACK = object_new( "BUILTIN_GLOB_BACK" );
+ constant_timestamp = object_new( "timestamp" );
+ constant_python = object_new("__python__");
+ constant_python_interface = object_new( "python_interface" );
+ constant_extra_pythonpath = object_new( "EXTRA_PYTHONPATH" );
+ constant_MAIN_PYTHON = object_new( "MAIN_PYTHON" );
 }
 
 void constants_done( void )
 {
     object_free( constant_empty );
     object_free( constant_dot );
- object_free( constant_percent );
     object_free( constant_plus );
     object_free( constant_star );
     object_free( constant_question_mark );
@@ -85,6 +85,7 @@
     object_free( constant_true );
     object_free( constant_name );
     object_free( constant_bases );
+ object_free( constant_class );
     object_free( constant_typecheck );
     object_free( constant_builtin );
     object_free( constant_HCACHEFILE );
@@ -104,6 +105,7 @@
     object_free( constant_STDOUT );
     object_free( constant_STDERR );
     object_free( constant_JAMDATE );
+ object_free( constant_JAM_TIMESTAMP_RESOLUTION );
     object_free( constant_JAM_VERSION );
     object_free( constant_JAMUNAME );
     object_free( constant_ENVIRON );
@@ -131,7 +133,6 @@
 
 OBJECT * constant_empty;
 OBJECT * constant_dot;
-OBJECT * constant_percent;
 OBJECT * constant_plus;
 OBJECT * constant_star;
 OBJECT * constant_question_mark;
@@ -139,6 +140,7 @@
 OBJECT * constant_true;
 OBJECT * constant_name;
 OBJECT * constant_bases;
+OBJECT * constant_class;
 OBJECT * constant_typecheck;
 OBJECT * constant_builtin;
 OBJECT * constant_HCACHEFILE;
@@ -177,6 +179,7 @@
 OBJECT * constant_IMPORT_MODULE;
 OBJECT * constant_BUILTIN_GLOB_BACK;
 OBJECT * constant_timestamp;
+OBJECT * constant_JAM_TIMESTAMP_RESOLUTION;
 OBJECT * constant_python;
 OBJECT * constant_python_interface;
 OBJECT * constant_extra_pythonpath;

Modified: branches/release/tools/build/v2/engine/constants.h
==============================================================================
--- branches/release/tools/build/v2/engine/constants.h (original)
+++ branches/release/tools/build/v2/engine/constants.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -16,57 +16,58 @@
 void constants_init( void );
 void constants_done( void );
 
-extern OBJECT * constant_empty; /* "" */
-extern OBJECT * constant_dot; /* "." */
-extern OBJECT * constant_percent; /* "%" */
-extern OBJECT * constant_plus; /* "+" */
-extern OBJECT * constant_star; /* "*" */
-extern OBJECT * constant_question_mark; /* "?" */
-extern OBJECT * constant_ok; /* "ok" */
-extern OBJECT * constant_true; /* "true" */
-extern OBJECT * constant_name; /* "__name__" */
-extern OBJECT * constant_bases; /* "__bases__" */
-extern OBJECT * constant_typecheck; /* ".typecheck" */
-extern OBJECT * constant_builtin; /* "(builtin)" */
-extern OBJECT * constant_HCACHEFILE; /* "HCACHEFILE" */
-extern OBJECT * constant_HCACHEMAXAGE; /* "HCACHEMAXAGE" */
-extern OBJECT * constant_HDRSCAN; /* "HDRSCAN" */
-extern OBJECT * constant_HDRRULE; /* "HDRRULE" */
-extern OBJECT * constant_BINDRULE; /* "BINDRULE" */
-extern OBJECT * constant_LOCATE; /* "LOCATE" */
-extern OBJECT * constant_SEARCH; /* "SEARCH" */
-extern OBJECT * constant_JAM_SEMAPHORE; /* "JAM_SEMAPHORE" */
-extern OBJECT * constant_TIMING_RULE; /* "__TIMING_RULE__" */
-extern OBJECT * constant_ACTION_RULE; /* "__ACTION_RULE__" */
-extern OBJECT * constant_JAMSHELL; /* "JAMSHELL" */
-extern OBJECT * constant_TMPDIR; /* "TMPDIR" */
-extern OBJECT * constant_TMPNAME; /* "TMPNAME" */
-extern OBJECT * constant_TMPFILE; /* "TMPFILE" */
-extern OBJECT * constant_STDOUT; /* "STDOUT" */
-extern OBJECT * constant_STDERR; /* "STDERR" */
-extern OBJECT * constant_JAMDATE; /* "JAMDATE" */
-extern OBJECT * constant_JAM_VERSION; /* "JAM_VERSION" */
-extern OBJECT * constant_JAMUNAME; /* "JAMUNAME" */
-extern OBJECT * constant_ENVIRON; /* ".ENVIRON" */
-extern OBJECT * constant_ARGV; /* "ARGV" */
-extern OBJECT * constant_all; /* "all" */
-extern OBJECT * constant_PARALLELISM; /* "PARALLELISM" */
-extern OBJECT * constant_KEEP_GOING; /* "KEEP_GOING" */
-extern OBJECT * constant_other; /* "[OTHER]" */
-extern OBJECT * constant_total; /* "[TOTAL]" */
-extern OBJECT * constant_FILE_DIRSCAN; /* "FILE_DIRSCAN" */
-extern OBJECT * constant_MAIN; /* "MAIN" */
-extern OBJECT * constant_MAIN_MAKE; /* "MAIN_MAKE" */
-extern OBJECT * constant_MAKE_MAKE0; /* "MAKE_MAKE0" */
-extern OBJECT * constant_MAKE_MAKE1; /* "MAKE_MAKE1" */
-extern OBJECT * constant_MAKE_MAKE0SORT; /* "MAKE_MAKE0SORT" */
-extern OBJECT * constant_BINDMODULE; /* "BINDMODULE" */
-extern OBJECT * constant_IMPORT_MODULE; /* "IMPORT_MODULE" */
-extern OBJECT * constant_BUILTIN_GLOB_BACK; /* "BUILTIN_GLOB_BACK" */
-extern OBJECT * constant_timestamp; /* "timestamp" */
-extern OBJECT * constant_python; /* "__python__" */
-extern OBJECT * constant_python_interface; /* "python_interface" */
-extern OBJECT * constant_extra_pythonpath; /* "EXTRA_PYTHONPATH" */
-extern OBJECT * constant_MAIN_PYTHON; /* "MAIN_PYTHON" */
+extern OBJECT * constant_empty; /* "" */
+extern OBJECT * constant_dot; /* "." */
+extern OBJECT * constant_plus; /* "+" */
+extern OBJECT * constant_star; /* "*" */
+extern OBJECT * constant_question_mark; /* "?" */
+extern OBJECT * constant_ok; /* "ok" */
+extern OBJECT * constant_true; /* "true" */
+extern OBJECT * constant_name; /* "__name__" */
+extern OBJECT * constant_bases; /* "__bases__" */
+extern OBJECT * constant_class; /* "__class__" */
+extern OBJECT * constant_typecheck; /* ".typecheck" */
+extern OBJECT * constant_builtin; /* "(builtin)" */
+extern OBJECT * constant_HCACHEFILE; /* "HCACHEFILE" */
+extern OBJECT * constant_HCACHEMAXAGE; /* "HCACHEMAXAGE" */
+extern OBJECT * constant_HDRSCAN; /* "HDRSCAN" */
+extern OBJECT * constant_HDRRULE; /* "HDRRULE" */
+extern OBJECT * constant_BINDRULE; /* "BINDRULE" */
+extern OBJECT * constant_LOCATE; /* "LOCATE" */
+extern OBJECT * constant_SEARCH; /* "SEARCH" */
+extern OBJECT * constant_JAM_SEMAPHORE; /* "JAM_SEMAPHORE" */
+extern OBJECT * constant_TIMING_RULE; /* "__TIMING_RULE__" */
+extern OBJECT * constant_ACTION_RULE; /* "__ACTION_RULE__" */
+extern OBJECT * constant_JAMSHELL; /* "JAMSHELL" */
+extern OBJECT * constant_TMPDIR; /* "TMPDIR" */
+extern OBJECT * constant_TMPNAME; /* "TMPNAME" */
+extern OBJECT * constant_TMPFILE; /* "TMPFILE" */
+extern OBJECT * constant_STDOUT; /* "STDOUT" */
+extern OBJECT * constant_STDERR; /* "STDERR" */
+extern OBJECT * constant_JAMDATE; /* "JAMDATE" */
+extern OBJECT * constant_JAM_TIMESTAMP_RESOLUTION; /* "JAM_TIMESTAMP_RESOLUTION" */
+extern OBJECT * constant_JAM_VERSION; /* "JAM_VERSION" */
+extern OBJECT * constant_JAMUNAME; /* "JAMUNAME" */
+extern OBJECT * constant_ENVIRON; /* ".ENVIRON" */
+extern OBJECT * constant_ARGV; /* "ARGV" */
+extern OBJECT * constant_all; /* "all" */
+extern OBJECT * constant_PARALLELISM; /* "PARALLELISM" */
+extern OBJECT * constant_KEEP_GOING; /* "KEEP_GOING" */
+extern OBJECT * constant_other; /* "[OTHER]" */
+extern OBJECT * constant_total; /* "[TOTAL]" */
+extern OBJECT * constant_FILE_DIRSCAN; /* "FILE_DIRSCAN" */
+extern OBJECT * constant_MAIN; /* "MAIN" */
+extern OBJECT * constant_MAIN_MAKE; /* "MAIN_MAKE" */
+extern OBJECT * constant_MAKE_MAKE0; /* "MAKE_MAKE0" */
+extern OBJECT * constant_MAKE_MAKE1; /* "MAKE_MAKE1" */
+extern OBJECT * constant_MAKE_MAKE0SORT; /* "MAKE_MAKE0SORT" */
+extern OBJECT * constant_BINDMODULE; /* "BINDMODULE" */
+extern OBJECT * constant_IMPORT_MODULE; /* "IMPORT_MODULE" */
+extern OBJECT * constant_BUILTIN_GLOB_BACK; /* "BUILTIN_GLOB_BACK" */
+extern OBJECT * constant_timestamp; /* "timestamp" */
+extern OBJECT * constant_python; /* "__python__" */
+extern OBJECT * constant_python_interface; /* "python_interface" */
+extern OBJECT * constant_extra_pythonpath; /* "EXTRA_PYTHONPATH" */
+extern OBJECT * constant_MAIN_PYTHON; /* "MAIN_PYTHON" */
 
 #endif

Modified: branches/release/tools/build/v2/engine/debug.c
==============================================================================
--- branches/release/tools/build/v2/engine/debug.c (original)
+++ branches/release/tools/build/v2/engine/debug.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,21 +1,20 @@
 /*
- Copyright Rene Rivera 2005.
- 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)
-*/
+ * Copyright 2005. Rene Rivera
+ * 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)
+ */
 
 #include "jam.h"
+#include "debug.h"
 
 #include "hash.h"
 
-#include <time.h>
-#include <assert.h>
-
 
 static profile_frame * profile_stack = 0;
 static struct hash * profile_hash = 0;
-static profile_info profile_other = { 0, 0, 0, 0, 0, 0 };
-static profile_info profile_total = { 0, 0, 0, 0, 0, 0 };
+static profile_info profile_other = { 0 };
+static profile_info profile_total = { 0 };
 
 
 profile_frame * profile_init( OBJECT * rulename, profile_frame * frame )
@@ -42,7 +41,11 @@
             if ( !found )
             {
                 p->name = rulename;
- p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ p->cumulative = 0;
+ p->net = 0;
+ p->num_entries = 0;
+ p->stack_count = 0;
+ p->memory = 0;
             }
         }
         else
@@ -82,8 +85,8 @@
     if ( DEBUG_PROFILE )
     {
         /* Cumulative time for this call. */
- clock_t t = clock() - frame->entry_time - frame->overhead;
- /* If this rule is already present on the stack, don't add the time for
+ clock_t const t = clock() - frame->entry_time - frame->overhead;
+ /* If this rule is already present on the stack, do not add the time for
          * this instance.
          */
         if ( frame->info->stack_count == 1 )
@@ -108,7 +111,8 @@
 static void dump_profile_entry( void * p_, void * ignored )
 {
     profile_info * p = (profile_info *)p_;
- unsigned long mem_each = ( p->memory / ( p->num_entries ? p->num_entries : 1 ) );
+ unsigned long mem_each = ( p->memory / ( p->num_entries ? p->num_entries : 1
+ ) );
     double cumulative = p->cumulative;
     double net = p->net;
     double q = p->net;

Modified: branches/release/tools/build/v2/engine/debug.h
==============================================================================
--- branches/release/tools/build/v2/engine/debug.h (original)
+++ branches/release/tools/build/v2/engine/debug.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,17 +1,19 @@
 /*
- Copyright Rene Rivera 2005.
- 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)
-*/
+ * Copyright 2005. Rene Rivera
+ * 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)
+ */
+
 #ifndef BJAM_DEBUG_H
 #define BJAM_DEBUG_H
 
 #include "constants.h"
-#include "jam.h"
+#include "object.h"
 #include <time.h>
 
 
-struct profile_info
+typedef struct profile_info
 {
     /* name of rule being called */
     OBJECT * name;
@@ -25,28 +27,26 @@
     unsigned long stack_count;
     /* bytes of memory allocated by the call */
     unsigned long memory;
-};
-typedef struct profile_info profile_info;
+} profile_info;
 
-struct profile_frame
+typedef struct profile_frame
 {
     /* permanent storage where data accumulates */
- profile_info* info;
+ profile_info * info;
     /* overhead for profiling in this call */
     clock_t overhead;
     /* time of last entry to rule */
     clock_t entry_time;
     /* stack frame of caller */
- struct profile_frame* caller;
+ struct profile_frame * caller;
     /* time spent in subrules */
     clock_t subrules;
-};
-typedef struct profile_frame profile_frame;
+} profile_frame;
 
-profile_frame * profile_init( OBJECT * rulename, profile_frame * frame );
-void profile_enter( OBJECT * rulename, profile_frame * frame );
+profile_frame * profile_init( OBJECT * rulename, profile_frame * );
+void profile_enter( OBJECT * rulename, profile_frame * );
 void profile_memory( long mem );
-void profile_exit( profile_frame * frame );
+void profile_exit( profile_frame * );
 void profile_dump();
 
 #define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( constant_ ## scope, &PROF_ ## scope )

Copied: branches/release/tools/build/v2/engine/execcmd.c (from r79057, /trunk/tools/build/v2/engine/execcmd.c)
==============================================================================
--- /trunk/tools/build/v2/engine/execcmd.c (original)
+++ branches/release/tools/build/v2/engine/execcmd.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,11 +11,99 @@
 #include "jam.h"
 #include "execcmd.h"
 
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
 
 /* Internal interrupt counter. */
 static int intr;
 
 
+/* Constructs a list of command-line elements using the format specified by the
+ * given shell list.
+ *
+ * Given argv array should have at least MAXARGC + 1 elements.
+ * Slot numbers may be between 0 and 998 (inclusive).
+ *
+ * Constructed argv list will be zero terminated. Character arrays referenced by
+ * the argv structure elements will be either elements from the give shell list,
+ * internal static buffers or the given command string and should thus not
+ * considered owned by or released via the argv structure and should be
+ * considered invalidated by the next argv_from_shell() call.
+ *
+ * Shell list elements:
+ * - Starting with '%' - represent the command string.
+ * - Starting with '!' - represent the slot number (increased by one).
+ * - Anything else - used as a literal.
+ * - If no '%' element is found, the command string is appended as an extra.
+ */
+
+void argv_from_shell( char const * * argv, LIST * shell, char const * command,
+ int const slot )
+{
+ static char jobno[ 4 ];
+
+ int i;
+ int gotpercent = 0;
+ LISTITER iter = list_begin( shell );
+ LISTITER end = list_end( shell );
+
+ assert( 0 <= slot );
+ assert( slot < 999 );
+ sprintf( jobno, "%d", slot + 1 );
+
+ for ( i = 0; iter != end && i < MAXARGC; ++i, iter = list_next( iter ) )
+ {
+ switch ( object_str( list_item( iter ) )[ 0 ] )
+ {
+ case '%': argv[ i ] = command; ++gotpercent; break;
+ case '!': argv[ i ] = jobno; break;
+ default : argv[ i ] = object_str( list_item( iter ) );
+ }
+ }
+
+ if ( !gotpercent )
+ argv[ i++ ] = command;
+
+ argv[ i ] = NULL;
+}
+
+
+/* Returns whether the given command string contains lines longer than the given
+ * maximum.
+ */
+int check_cmd_for_too_long_lines( char const * command, int const max,
+ int * const error_length, int * const error_max_length )
+{
+ while ( *command )
+ {
+ size_t const l = strcspn( command, "\n" );
+ if ( l > max )
+ {
+ *error_length = l;
+ *error_max_length = max;
+ return EXEC_CHECK_LINE_TOO_LONG;
+ }
+ command += l;
+ if ( *command )
+ ++command;
+ }
+ return EXEC_CHECK_OK;
+}
+
+
+/* Checks whether the given shell list is actually a request to execute raw
+ * commands without an external shell.
+ */
+int is_raw_command_request( LIST * shell )
+{
+ return !list_empty( shell ) &&
+ !strcmp( object_str( list_front( shell ) ), "%" ) &&
+ list_next( list_begin( shell ) ) == list_end( shell );
+}
+
+
 /* Returns whether an interrupt has been detected so far. */
 
 int interrupted( void )

Modified: branches/release/tools/build/v2/engine/execcmd.h
==============================================================================
--- branches/release/tools/build/v2/engine/execcmd.h (original)
+++ branches/release/tools/build/v2/engine/execcmd.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,40 +8,95 @@
  * execcmd.h - execute a shell script.
  *
  * Defines the interface to be implemented in platform specific implementation
- * modules.
- *
- * 05/04/94 (seiwald) - async multiprocess interface
+ * modules as well as different shared utility functions prepared in the
+ * execcmd.c module.
  */
 
 #ifndef EXECCMD_H
 #define EXECCMD_H
 
-#include <time.h>
+#include "lists.h"
+#include "strings.h"
+#include "timestamp.h"
+
 
 typedef struct timing_info
 {
     double system;
     double user;
- time_t start;
- time_t end;
+ timestamp start;
+ timestamp end;
 } timing_info;
 
+typedef void (* ExecCmdCallback)
+(
+ void * const closure,
+ int const status,
+ timing_info const * const,
+ char const * const cmd_stdout,
+ char const * const cmd_stderr,
+ int const cmd_exit_reason
+);
+
+/* Status codes passed to ExecCmdCallback routines. */
+#define EXEC_CMD_OK 0
+#define EXEC_CMD_FAIL 1
+#define EXEC_CMD_INTR 2
+
+int exec_check
+(
+ string const * command,
+ LIST * * pShell,
+ int * error_length,
+ int * error_max_length
+);
+
+/* exec_check() return codes. */
+#define EXEC_CHECK_OK 101
+#define EXEC_CHECK_NOOP 102
+#define EXEC_CHECK_LINE_TOO_LONG 103
+#define EXEC_CHECK_TOO_LONG 104
+
 void exec_cmd
 (
- const char * string,
- void (* func)( void * closure, int status, timing_info *, const char *, const char * ),
+ string const * command,
+ ExecCmdCallback func,
     void * closure,
- LIST * shell,
- const char * action,
- const char * target
+ LIST * shell
 );
 
-int exec_wait();
+void exec_wait();
 
-void exec_done( void );
 
-#define EXEC_CMD_OK 0
-#define EXEC_CMD_FAIL 1
-#define EXEC_CMD_INTR 2
+/******************************************************************************
+ * *
+ * Utility functions defined in the execcmd.c module. *
+ * *
+ ******************************************************************************/
+
+/* Constructs a list of command-line elements using the format specified by the
+ * given shell list.
+ */
+void argv_from_shell( char const * * argv, LIST * shell, char const * command,
+ int const slot );
+
+/* Interrupt routine bumping the internal interrupt counter. Needs to be
+ * registered by platform specific exec*.c modules.
+ */
+void onintr( int disp );
+
+/* Returns whether an interrupt has been detected so far. */
+int interrupted( void );
+
+/* Checks whether the given shell list is actually a request to execute raw
+ * commands without an external shell.
+ */
+int is_raw_command_request( LIST * shell );
+
+/* Utility worker for exec_check() checking whether all the given command lines
+ * are under the specified length limit.
+ */
+int check_cmd_for_too_long_lines( char const * command, int const max,
+ int * const error_length, int * const error_max_length );
 
 #endif

Modified: branches/release/tools/build/v2/engine/execnt.c
==============================================================================
--- branches/release/tools/build/v2/engine/execnt.c (original)
+++ branches/release/tools/build/v2/engine/execnt.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,122 +4,125 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Copyright 2007 Rene Rivera.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * Copyright 2007 Rene Rivera.
+ * 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)
+ */
+
+/*
+ * execnt.c - execute a shell command on Windows NT
+ *
+ * If $(JAMSHELL) is defined, uses that to formulate the actual command. The
+ * default is: cmd.exe /Q/C
+ *
+ * In $(JAMSHELL), % expands to the command string and ! expands to the slot
+ * number (starting at 1) for multiprocess (-j) invocations. If $(JAMSHELL) does
+ * not include a %, it is tacked on as the last argument.
+ *
+ * Each $(JAMSHELL) placeholder must be specified as a separate individual
+ * element in a jam variable value.
+ *
+ * Do not just set JAMSHELL to cmd.exe - it will not work!
+ *
+ * External routines:
+ * exec_check() - preprocess and validate the command
+ * exec_cmd() - launch an async command execution
+ * exec_wait() - wait for any of the async command processes to terminate
+ *
+ * Internal routines:
+ * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
  */
 
 #include "jam.h"
-#include "lists.h"
+#ifdef USE_EXECNT
 #include "execcmd.h"
+
+#include "lists.h"
+#include "output.h"
 #include "pathsys.h"
 #include "string.h"
-#include "output.h"
-#include <errno.h>
+
 #include <assert.h>
 #include <ctype.h>
+#include <errno.h>
 #include <time.h>
-#include <math.h>
-
-#ifdef USE_EXECNT
 
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <process.h>
 #include <tlhelp32.h>
 
-/*
- * execnt.c - execute a shell command on Windows NT
- *
- * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
- * The default is:
- *
- * /bin/sh -c % [ on UNIX/AmigaOS ]
- * cmd.exe /c % [ on Windows NT ]
- *
- * Each word must be an individual element in a jam variable value.
- *
- * In $(JAMSHELL), % expands to the command string and ! expands to
- * the slot number (starting at 1) for multiprocess (-j) invocations.
- * If $(JAMSHELL) doesn't include a %, it is tacked on as the last
- * argument.
- *
- * Don't just set JAMSHELL to /bin/sh or cmd.exe - it won't work!
- *
- * External routines:
- * exec_cmd() - launch an async command execution.
- * exec_wait() - wait and drive at most one execution completion.
- *
- * Internal routines:
- * onintr() - bump intr to note command interruption.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 05/04/94 (seiwald) - async multiprocess interface
- * 01/22/95 (seiwald) - $(JAMSHELL) support
- * 06/02/97 (gsar) - full async multiprocess support for Win32
- */
-
-/* get the maximum command line length according to the OS */
-int maxline();
-
-/* delete and argv list */
-static void free_argv(const char * *);
-/* Convert a command string into arguments for spawnvp. */
-static const char** string_to_args(const char*);
-/* bump intr to note command interruption */
-static void onintr(int);
-/* If the command is suitable for execution via spawnvp */
-long can_spawn(const char*);
-/* Add two 64-bit unsigned numbers, h1l1 and h2l2 */
+
+/* get the maximum shell command line length according to the OS */
+static int maxline();
+/* valid raw command string length */
+static long raw_command_length( char const * command );
+/* add two 64-bit unsigned numbers, h1l1 and h2l2 */
 static FILETIME add_64(
     unsigned long h1, unsigned long l1,
- unsigned long h2, unsigned long l2);
-static FILETIME add_FILETIME(FILETIME t1, FILETIME t2);
-static FILETIME negate_FILETIME(FILETIME t);
-/* Convert a FILETIME to a number of seconds */
-static double filetime_seconds(FILETIME t);
+ unsigned long h2, unsigned long l2 );
+/* */
+static FILETIME add_FILETIME( FILETIME t1, FILETIME t2 );
+/* */
+static FILETIME negate_FILETIME( FILETIME t );
 /* record the timing info for the process */
-static void record_times(HANDLE, timing_info*);
+static void record_times( HANDLE const, timing_info * const );
 /* calc the current running time of an *active* process */
-static double running_time(HANDLE);
-/* */
-DWORD get_process_id(HANDLE);
-/* terminate the given process, after terminating all its children */
-static void kill_process_tree(DWORD, HANDLE);
-/* waits for a command to complete or for the given timeout, whichever is first */
-static int try_wait(int timeoutMillis);
+static double running_time( HANDLE const );
+/* terminate the given process, after terminating all its children first */
+static void kill_process_tree( DWORD const procesdId, HANDLE const );
+/* waits for a command to complete or time out */
+static int try_wait( int const timeoutMillis );
 /* reads any pending output for running commands */
 static void read_output();
 /* checks if a command ran out of time, and kills it */
 static int try_kill_one();
+/* is the first process a parent (direct or indirect) to the second one */
+static int is_parent_child( DWORD const parent, DWORD const child );
 /* */
-static double creation_time(HANDLE);
-/* Recursive check if first process is parent (directly or indirectly) of
-the second one. */
-static int is_parent_child(DWORD, DWORD);
-/* */
-static void close_alert(HANDLE);
+static void close_alert( PROCESS_INFORMATION const * const );
 /* close any alerts hanging around */
 static void close_alerts();
+/* prepare a command file to be executed using an external shell */
+static char const * prepare_command_file( string const * command, int slot );
+/* invoke the actual external process using the given command line */
+static void invoke_cmd( char const * const command, int const slot );
+/* find a free slot in the running commands table */
+static int get_free_cmdtab_slot();
+/* put together the final command string we are to run */
+static void string_new_from_argv( string * result, char const * const * argv );
+/* frees and renews the given string */
+static void string_renew( string * const );
+/* reports the last failed Windows API related error message */
+static void reportWindowsError( char const * const apiName );
+/* closes a Windows HANDLE and resets its variable to 0. */
+static void closeWinHandle( HANDLE * const handle );
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
-static int intr = 0;
-static int cmdsrunning = 0;
-static void (* istat)( int );
+/* CreateProcessA() Windows API places a limit of 32768 characters (bytes) on
+ * the allowed command-line length, including a trailing Unicode (2-byte)
+ * nul-terminator character.
+ */
+#define MAX_RAW_COMMAND_LENGTH 32766
+
+/* We hold handles for pipes used to communicate with child processes in two
+ * element arrays indexed as follows.
+ */
+#define EXECCMD_PIPE_READ 0
+#define EXECCMD_PIPE_WRITE 1
+
+static int intr_installed;
 
 
 /* The list of commands we run. */
 static struct
 {
- string action; /* buffer to hold action */
- string target; /* buffer to hold target */
- string command; /* buffer to hold command being invoked */
-
- /* Temporary batch file used to execute the action when needed. */
- char * tempfile_bat;
+ /* Temporary command file used to execute the action when needed. */
+ string command_file[ 1 ];
 
     /* Pipes for communicating with the child process. Parent reads from (0),
      * child writes to (1).
@@ -127,19 +130,15 @@
     HANDLE pipe_out[ 2 ];
     HANDLE pipe_err[ 2 ];
 
- string buffer_out; /* buffer to hold stdout, if any */
- string buffer_err; /* buffer to hold stderr, if any */
+ string buffer_out[ 1 ]; /* buffer to hold stdout, if any */
+ string buffer_err[ 1 ]; /* buffer to hold stderr, if any */
 
- PROCESS_INFORMATION pi; /* running process information */
- DWORD exit_code; /* executed command's exit code */
- int exit_reason; /* reason why a command completed */
+ PROCESS_INFORMATION pi; /* running process information */
 
     /* Function called when the command completes. */
- void (* func)( void * closure, int status, timing_info *, const char *, const char * );
+ ExecCmdCallback func;
 
- /* Opaque data passed back to the 'func' callback called when the command
- * completes.
- */
+ /* Opaque data passed back to the 'func' callback. */
     void * closure;
 }
 cmdtab[ MAXJOBS ] = { { 0 } };
@@ -155,433 +154,350 @@
     /* vc6 preprocessor is broken, so assert with these strings gets confused.
      * Use a table instead.
      */
- typedef struct test { char * command; int result; } test;
- test tests[] = {
- { "x", 0 },
- { "x\n ", 0 },
- { "x\ny", 1 },
- { "x\n\n y", 1 },
- { "echo x > foo.bar", 1 },
- { "echo x < foo.bar", 1 },
- { "echo x \">\" foo.bar", 0 },
- { "echo x \"<\" foo.bar", 0 },
- { "echo x \\\">\\\" foo.bar", 1 },
- { "echo x \\\"<\\\" foo.bar", 1 } };
- int i;
- for ( i = 0; i < sizeof( tests ) / sizeof( *tests ); ++i )
- assert( !can_spawn( tests[ i ].command ) == tests[ i ].result );
-
     {
- char * long_command = BJAM_MALLOC_ATOMIC( MAXLINE + 10 );
- assert( long_command != 0 );
- memset( long_command, 'x', MAXLINE + 9 );
- long_command[ MAXLINE + 9 ] = 0;
- assert( can_spawn( long_command ) == MAXLINE + 9 );
- BJAM_FREE( long_command );
+ typedef struct test { char * command; int result; } test;
+ test tests[] = {
+ { "", 0 },
+ { " ", 0 },
+ { "x", 1 },
+ { "\nx", 1 },
+ { "x\n", 1 },
+ { "\nx\n", 1 },
+ { "\nx \n", 2 },
+ { "\nx \n ", 2 },
+ { " \n\t\t\v\r\r\n \t x \v \t\t\r\n\n\n \n\n\v\t", 8 },
+ { "x\ny", -1 },
+ { "x\n\n y", -1 },
+ { "echo x > foo.bar", -1 },
+ { "echo x < foo.bar", -1 },
+ { "echo x | foo.bar", -1 },
+ { "echo x \">\" foo.bar", 18 },
+ { "echo x '<' foo.bar", 18 },
+ { "echo x \"|\" foo.bar", 18 },
+ { "echo x \\\">\\\" foo.bar", -1 },
+ { "echo x \\\"<\\\" foo.bar", -1 },
+ { "echo x \\\"|\\\" foo.bar", -1 },
+ { "\"echo x > foo.bar\"", 18 },
+ { "echo x \"'\"<' foo.bar", -1 },
+ { "echo x \\\\\"<\\\\\" foo.bar", 22 },
+ { "echo x \\x\\\"<\\\\\" foo.bar", -1 },
+ { 0 } };
+ test const * t;
+ for ( t = tests; t->command; ++t )
+ assert( raw_command_length( t->command ) == t->result );
     }
 
     {
- /* Work around vc6 bug; it doesn't like escaped string
- * literals inside assert
- */
- const char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
- char const expected[] = "-c -I\"Foobar\"";
-
- assert( !strcmp( argv[ 0 ], "g++" ) );
- assert( !strcmp( argv[ 1 ], expected ) );
- free_argv( argv );
+ int const length = maxline() + 9;
+ char * const cmd = (char *)BJAM_MALLOC_ATOMIC( length + 1 );
+ memset( cmd, 'x', length );
+ cmd[ length ] = 0;
+ assert( raw_command_length( cmd ) == length );
+ BJAM_FREE( cmd );
     }
 #endif
 }
 
 
 /*
- * exec_cmd() - launch an async command execution.
+ * exec_check() - preprocess and validate the command
  */
 
-void exec_cmd
+int exec_check
 (
- const char * command,
- void (* func)( void * closure, int status, timing_info *, const char * invoked_command, const char * command_output ),
- void * closure,
- LIST * shell,
- const char * action,
- const char * target
+ string const * command,
+ LIST * * pShell,
+ int * error_length,
+ int * error_max_length
 )
 {
- int slot;
- int raw_cmd = 0 ;
- const char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
- const char * * argv = argv_static;
- char * p;
- const char * command_orig = command;
-
- /* Check to see if we need to hack around the line-length limitation. Look
- * for a JAMSHELL setting of "%", indicating that the command should be
- * invoked directly.
+ /* Default shell does nothing when triggered with an empty or a
+ * whitespace-only command so we simply skip running it in that case. We
+ * still pass them on to non-default shells as we do not really know what
+ * they are going to do with such commands.
      */
- if ( !list_empty( shell ) && !strcmp( object_str( list_front( shell ) ), "%" ) && list_next( list_begin( shell ) ) == list_end( shell ) )
+ if ( list_empty( *pShell ) )
     {
- raw_cmd = 1;
- shell = 0;
+ char const * s = command->value;
+ while ( isspace( *s ) ) ++s;
+ if ( !*s )
+ return EXEC_CHECK_NOOP;
     }
 
- /* Find a slot in the running commands table for this one. */
- for ( slot = 0; slot < MAXJOBS; ++slot )
- if ( !cmdtab[ slot ].pi.hProcess )
- break;
- if ( slot == MAXJOBS )
- {
- printf( "no slots for child!\n" );
- exit( EXITBAD );
- }
-
- /* Compute the name of a temp batch file, for possible use. */
- if ( !cmdtab[ slot ].tempfile_bat )
- {
- char const * tempdir = path_tmpdir();
- DWORD procID = GetCurrentProcessId();
-
- /* SVA - allocate 64 bytes extra just to be safe. */
- cmdtab[ slot ].tempfile_bat = BJAM_MALLOC_ATOMIC( strlen( tempdir ) + 64 );
-
- sprintf( cmdtab[ slot ].tempfile_bat, "%s\\jam%d-%02d.bat",
- tempdir, procID, slot );
- }
-
- /* Trim leading, -ending- white space */
- while ( *( command + 1 ) && isspace( *command ) )
- ++command;
-
- /* Write to .BAT file unless the line would be too long and it meets the
- * other spawnability criteria.
- */
- if ( raw_cmd && ( can_spawn( command ) >= MAXLINE ) )
- {
- if ( DEBUG_EXECCMD )
- printf("Executing raw command directly\n");
- }
- else
+ /* Check prerequisites for executing raw commands. */
+ if ( is_raw_command_request( *pShell ) )
     {
- FILE * f = 0;
- int tries = 0;
- raw_cmd = 0;
-
- /* Write command to bat file. For some reason this open can fail
- * intermitently. But doing some retries works. Most likely this is due
- * to a previously existing file of the same name that happens to be
- * opened by an active virus scanner. Pointed out and fixed by Bronek
- * Kozicki.
- */
- for ( ; !f && ( tries < 4 ); ++tries )
+ int const raw_cmd_length = raw_command_length( command->value );
+ if ( raw_cmd_length < 0 )
         {
- f = fopen( cmdtab[ slot ].tempfile_bat, "w" );
- if ( !f && ( tries < 4 ) ) Sleep( 250 );
+ /* Invalid characters detected - fallback to default shell. */
+ list_free( *pShell );
+ *pShell = L0;
         }
- if ( !f )
+ else if ( raw_cmd_length > MAX_RAW_COMMAND_LENGTH )
         {
- printf( "failed to write command file!\n" );
- exit( EXITBAD );
- }
- fputs( command, f );
- fclose( f );
-
- command = cmdtab[ slot ].tempfile_bat;
-
- if ( DEBUG_EXECCMD )
- {
- if ( !list_empty( shell ) )
- printf( "using user-specified shell: %s", object_str( list_front( shell ) ) );
- else
- printf( "Executing through .bat file\n" );
+ *error_length = raw_cmd_length;
+ *error_max_length = MAX_RAW_COMMAND_LENGTH;
+ return EXEC_CHECK_TOO_LONG;
         }
+ else
+ return raw_cmd_length ? EXEC_CHECK_OK : EXEC_CHECK_NOOP;
     }
 
- /* Formulate argv; If shell was defined, be prepared for % and ! subs.
- * Otherwise, use stock cmd.exe.
+ /* Now we know we are using an external shell. Note that there is no need to
+ * check for too long command strings when using an external shell since we
+ * use a command file and assume no one is going to set up a JAMSHELL format
+ * string longer than a few hundred bytes at most which should be well under
+ * the total command string limit. Should someone actually construct such a
+ * JAMSHELL value it will get reported as an 'invalid parameter'
+ * CreateProcessA() Windows API failure which seems like a good enough
+ * result for such intentional mischief.
      */
- if ( shell )
- {
- int i;
- char jobno[ 4 ];
- int gotpercent = 0;
- LISTITER shell_iter = list_begin( shell ), shell_end = list_end( shell );
 
- sprintf( jobno, "%d", slot + 1 );
+ /* Check for too long command lines. */
+ return check_cmd_for_too_long_lines( command->value, maxline(),
+ error_length, error_max_length );
+}
+
+
+/*
+ * exec_cmd() - launch an async command execution
+ *
+ * We assume exec_check() already verified that the given command can have its
+ * command string constructed as requested.
+ */
 
- for ( i = 0; shell_iter != shell_end && ( i < MAXARGC ); ++i, shell_iter = list_next( shell_iter ) )
+void exec_cmd
+(
+ string const * cmd_orig,
+ ExecCmdCallback func,
+ void * closure,
+ LIST * shell
+)
+{
+ int const slot = get_free_cmdtab_slot();
+ int const is_raw_cmd = is_raw_command_request( shell );
+ string cmd_local[ 1 ];
+
+ /* Initialize default shell - anything more than /Q/C is non-portable. */
+ static LIST * default_shell;
+ if ( !default_shell )
+ default_shell = list_new( object_new( "cmd.exe /Q/C" ) );
+
+ /* Specifying no shell means requesting the default shell. */
+ if ( list_empty( shell ) )
+ shell = default_shell;
+
+ if ( DEBUG_EXECCMD )
+ if ( is_raw_cmd )
+ printf( "Executing raw command directly\n" );
+ else
         {
- switch ( object_str( list_item( shell_iter ) )[ 0 ] )
- {
- case '%': argv[ i ] = command; ++gotpercent; break;
- case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = object_str( list_item( shell_iter ) );
- }
- if ( DEBUG_EXECCMD )
- printf( "argv[%d] = '%s'\n", i, argv[ i ] );
+ printf( "Executing using a command file and the shell: " );
+ list_print( shell );
+ printf( "\n" );
         }
 
- if ( !gotpercent )
- argv[ i++ ] = command;
-
- argv[ i ] = 0;
- }
- else if ( raw_cmd )
+ /* If we are running a raw command directly - trim its leading whitespaces
+ * as well as any trailing all-whitespace lines but keep any trailing
+ * whitespace in the final/only line containing something other than
+ * whitespace).
+ */
+ if ( is_raw_cmd )
     {
- argv = string_to_args( command );
- }
+ char const * start = cmd_orig->value;
+ char const * p = cmd_orig->value + cmd_orig->size;
+ char const * end = p;
+ while ( isspace( *start ) ) ++start;
+ while ( p > start && isspace( p[ -1 ] ) )
+ if ( *--p == '\n' )
+ end = p;
+ string_new( cmd_local );
+ string_append_range( cmd_local, start, end );
+ assert( cmd_local->size == raw_command_length( cmd_orig->value ) );
+ }
+ /* If we are not running a raw command directly, prepare a command file to
+ * be executed using an external shell and the actual command string using
+ * that command file.
+ */
     else
     {
- argv[ 0 ] = "cmd.exe";
- argv[ 1 ] = "/Q/C"; /* anything more is non-portable */
- argv[ 2 ] = command;
- argv[ 3 ] = 0;
+ char const * const cmd_file = prepare_command_file( cmd_orig, slot );
+ char const * argv[ MAXARGC + 1 ]; /* +1 for NULL */
+ argv_from_shell( argv, shell, cmd_file, slot );
+ string_new_from_argv( cmd_local, argv );
     }
 
     /* Catch interrupts whenever commands are running. */
- if ( !cmdsrunning++ )
- istat = signal( SIGINT, onintr );
-
- /* Start the command. */
+ if ( !intr_installed )
     {
- SECURITY_ATTRIBUTES sa
- = { sizeof( SECURITY_ATTRIBUTES ), 0, 0 };
- SECURITY_DESCRIPTOR sd;
- STARTUPINFO si
- = { sizeof( STARTUPINFO ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- string cmd;
-
- /* Init the security data. */
- InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION );
- SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE );
- sa.lpSecurityDescriptor = &sd;
- sa.bInheritHandle = TRUE;
-
- /* Create the stdout, which is also the merged out + err, pipe. */
- if ( !CreatePipe( &cmdtab[ slot ].pipe_out[ 0 ],
- &cmdtab[ slot ].pipe_out[ 1 ], &sa, 0 ) )
- {
- perror( "CreatePipe" );
- exit( EXITBAD );
- }
-
- /* Create the stdout, which is also the merged out+err, pipe. */
- if ( globs.pipe_action == 2 )
- {
- if ( !CreatePipe( &cmdtab[ slot ].pipe_err[ 0 ],
- &cmdtab[ slot ].pipe_err[ 1 ], &sa, 0 ) )
- {
- perror( "CreatePipe" );
- exit( EXITBAD );
- }
- }
-
- /* Set handle inheritance off for the pipe ends the parent reads from. */
- SetHandleInformation( cmdtab[ slot ].pipe_out[ 0 ], HANDLE_FLAG_INHERIT, 0 );
- if ( globs.pipe_action == 2 )
- SetHandleInformation( cmdtab[ slot ].pipe_err[ 0 ], HANDLE_FLAG_INHERIT, 0 );
-
- /* Hide the child window, if any. */
- si.dwFlags |= STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE;
-
- /* Set the child outputs to the pipes. */
- si.dwFlags |= STARTF_USESTDHANDLES;
- si.hStdOutput = cmdtab[ slot ].pipe_out[ 1 ];
- if ( globs.pipe_action == 2 )
- {
- /* Pipe stderr to the action error output. */
- si.hStdError = cmdtab[ slot ].pipe_err[ 1 ];
- }
- else if ( globs.pipe_action == 1 )
- {
- /* Pipe stderr to the console error output. */
- si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
- }
- else
- {
- /* Pipe stderr to the action merged output. */
- si.hStdError = cmdtab[ slot ].pipe_out[ 1 ];
- }
-
- /* Let the child inherit stdin, as some commands assume it's available. */
- si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
-
- /* Save the operation for exec_wait() to find. */
- cmdtab[ slot ].func = func;
- cmdtab[ slot ].closure = closure;
- if ( action && target )
- {
- string_copy( &cmdtab[ slot ].action, action );
- string_copy( &cmdtab[ slot ].target, target );
- }
- else
- {
- string_free( &cmdtab[ slot ].action );
- string_new ( &cmdtab[ slot ].action );
- string_free( &cmdtab[ slot ].target );
- string_new ( &cmdtab[ slot ].target );
- }
- string_copy( &cmdtab[ slot ].command, command_orig );
-
- /* Put together the command we run. */
- {
- const char * * argp = argv;
- string_new( &cmd );
- string_copy( &cmd, *(argp++) );
- while ( *argp )
- {
- string_push_back( &cmd, ' ' );
- string_append( &cmd, *(argp++) );
- }
- }
-
- /* Create output buffers. */
- string_new( &cmdtab[ slot ].buffer_out );
- string_new( &cmdtab[ slot ].buffer_err );
-
- /* Run the command by creating a sub-process for it. */
- if (
- ! CreateProcess(
- NULL , /* application name */
- cmd.value , /* command line */
- NULL , /* process attributes */
- NULL , /* thread attributes */
- TRUE , /* inherit handles */
- CREATE_NEW_PROCESS_GROUP, /* create flags */
- NULL , /* env vars, null inherits env */
- NULL , /* current dir, null is our */
- /* current dir */
- &si , /* startup info */
- &cmdtab[ slot ].pi /* child process info, if created */
- )
- )
- {
- perror( "CreateProcess" );
- exit( EXITBAD );
- }
-
- /* Clean up temporary stuff. */
- string_free( &cmd );
+ intr_installed = 1;
+ signal( SIGINT, onintr );
     }
 
- /* Wait until we are under the limit of concurrent commands. Do not trust
- * globs.jobs alone.
- */
- while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) )
- if ( !exec_wait() )
- break;
+ /* Save input data into the selected running commands table slot. */
+ cmdtab[ slot ].func = func;
+ cmdtab[ slot ].closure = closure;
 
- if ( argv != argv_static )
- free_argv( argv );
+ /* Invoke the actual external process using the constructed command line. */
+ invoke_cmd( cmd_local->value, slot );
+
+ /* Free our local command string copy. */
+ string_free( cmd_local );
 }
 
 
 /*
- * exec_wait()
- * * wait and drive at most one execution completion.
- * * waits for one command to complete, while processing the i/o for all
- * ongoing commands.
+ * exec_wait() - wait for any of the async command processes to terminate
  *
- * Returns 0 if called when there were no more commands being executed or 1
- * otherwise.
+ * Wait and drive at most one execution completion, while processing the I/O for
+ * all ongoing commands.
  */
 
-int exec_wait()
+void exec_wait()
 {
     int i = -1;
-
- /* Handle naive make1() which does not know if cmds are running. */
- if ( !cmdsrunning )
- return 0;
+ int exit_reason; /* reason why a command completed */
 
     /* Wait for a command to complete, while snarfing up any output. */
- do
+ while ( 1 )
     {
         /* Check for a complete command, briefly. */
- i = try_wait(500);
+ i = try_wait( 500 );
         /* Read in the output of all running commands. */
         read_output();
         /* Close out pending debug style dialogs. */
         close_alerts();
+ /* Process the completed command we found. */
+ if ( i >= 0 ) { exit_reason = EXIT_OK; break; }
         /* Check if a command ran out of time. */
- if ( i < 0 ) i = try_kill_one();
+ i = try_kill_one();
+ if ( i >= 0 ) { exit_reason = EXIT_TIMEOUT; break; }
     }
- while ( i < 0 );
 
     /* We have a command... process it. */
- --cmdsrunning;
     {
+ DWORD exit_code;
         timing_info time;
         int rstat;
 
         /* The time data for the command. */
         record_times( cmdtab[ i ].pi.hProcess, &time );
 
- /* Clear the temp file. */
- if ( cmdtab[ i ].tempfile_bat )
- {
- unlink( cmdtab[ i ].tempfile_bat );
- BJAM_FREE( cmdtab[ i ].tempfile_bat );
- cmdtab[ i ].tempfile_bat = NULL;
- }
+ /* Removed the used temporary command file. */
+ if ( cmdtab[ i ].command_file->size )
+ unlink( cmdtab[ i ].command_file->value );
 
         /* Find out the process exit code. */
- GetExitCodeProcess( cmdtab[ i ].pi.hProcess, &cmdtab[ i ].exit_code );
+ GetExitCodeProcess( cmdtab[ i ].pi.hProcess, &exit_code );
 
         /* The dispossition of the command. */
- if ( intr )
+ if ( interrupted() )
             rstat = EXEC_CMD_INTR;
- else if ( cmdtab[ i ].exit_code != 0 )
+ else if ( exit_code )
             rstat = EXEC_CMD_FAIL;
         else
             rstat = EXEC_CMD_OK;
 
- /* Output the action block. */
- out_action(
- cmdtab[ i ].action.size > 0 ? cmdtab[ i ].action.value : 0,
- cmdtab[ i ].target.size > 0 ? cmdtab[ i ].target.value : 0,
- cmdtab[ i ].command.size > 0 ? cmdtab[ i ].command.value : 0,
- cmdtab[ i ].buffer_out.size > 0 ? cmdtab[ i ].buffer_out.value : 0,
- cmdtab[ i ].buffer_err.size > 0 ? cmdtab[ i ].buffer_err.value : 0,
- cmdtab[ i ].exit_reason );
+ /* Call the callback, may call back to jam rule land. */
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time,
+ cmdtab[ i ].buffer_out->value, cmdtab[ i ].buffer_err->value,
+ exit_reason );
 
- /* Call the callback, may call back to jam rule land. Assume -p0 in
- * effect so only pass buffer containing merged output.
+ /* Clean up our child process tracking data. No need to clear the
+ * temporary command file name as it gets reused.
          */
- (*cmdtab[ i ].func)(
- cmdtab[ i ].closure,
- rstat,
- &time,
- cmdtab[ i ].command.value,
- cmdtab[ i ].buffer_out.value );
-
- /* Clean up the command data, process, etc. */
- string_free( &cmdtab[ i ].action ); string_new( &cmdtab[ i ].action );
- string_free( &cmdtab[ i ].target ); string_new( &cmdtab[ i ].target );
- string_free( &cmdtab[ i ].command ); string_new( &cmdtab[ i ].command );
- if ( cmdtab[ i ].pi.hProcess ) { CloseHandle( cmdtab[ i ].pi.hProcess ); cmdtab[ i ].pi.hProcess = 0; }
- if ( cmdtab[ i ].pi.hThread ) { CloseHandle( cmdtab[ i ].pi.hThread ); cmdtab[ i ].pi.hThread = 0; }
- if ( cmdtab[ i ].pipe_out[ 0 ] ) { CloseHandle( cmdtab[ i ].pipe_out[ 0 ] ); cmdtab[ i ].pipe_out[ 0 ] = 0; }
- if ( cmdtab[ i ].pipe_out[ 1 ] ) { CloseHandle( cmdtab[ i ].pipe_out[ 1 ] ); cmdtab[ i ].pipe_out[ 1 ] = 0; }
- if ( cmdtab[ i ].pipe_err[ 0 ] ) { CloseHandle( cmdtab[ i ].pipe_err[ 0 ] ); cmdtab[ i ].pipe_err[ 0 ] = 0; }
- if ( cmdtab[ i ].pipe_err[ 1 ] ) { CloseHandle( cmdtab[ i ].pipe_err[ 1 ] ); cmdtab[ i ].pipe_err[ 1 ] = 0; }
- string_free( &cmdtab[ i ].buffer_out ); string_new( &cmdtab[ i ].buffer_out );
- string_free( &cmdtab[ i ].buffer_err ); string_new( &cmdtab[ i ].buffer_err );
- cmdtab[ i ].exit_code = 0;
- cmdtab[ i ].exit_reason = EXIT_OK;
+ closeWinHandle( &cmdtab[ i ].pi.hProcess );
+ closeWinHandle( &cmdtab[ i ].pi.hThread );
+ closeWinHandle( &cmdtab[ i ].pipe_out[ EXECCMD_PIPE_READ ] );
+ closeWinHandle( &cmdtab[ i ].pipe_out[ EXECCMD_PIPE_WRITE ] );
+ closeWinHandle( &cmdtab[ i ].pipe_err[ EXECCMD_PIPE_READ ] );
+ closeWinHandle( &cmdtab[ i ].pipe_err[ EXECCMD_PIPE_WRITE ] );
+ string_renew( cmdtab[ i ].buffer_out );
+ string_renew( cmdtab[ i ].buffer_err );
     }
-
- return 1;
 }
 
 
 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 
-static void free_argv( const char * * args )
+/*
+ * Invoke the actual external process using the given command line. Track the
+ * process in our running commands table.
+ */
+
+static void invoke_cmd( char const * const command, int const slot )
 {
- BJAM_FREE( (void *)args[ 0 ] );
- BJAM_FREE( (void *)args );
+ SECURITY_ATTRIBUTES sa = { sizeof( SECURITY_ATTRIBUTES ), 0, 0 };
+ SECURITY_DESCRIPTOR sd;
+ STARTUPINFO si = { sizeof( STARTUPINFO ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0 };
+
+ /* Init the security data. */
+ InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION );
+ SetSecurityDescriptorDacl( &sd, TRUE, NULL, FALSE );
+ sa.lpSecurityDescriptor = &sd;
+ sa.bInheritHandle = TRUE;
+
+ /* Create pipes for communicating with the child process. */
+ if ( !CreatePipe( &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_READ ],
+ &cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ], &sa, 0 ) )
+ {
+ reportWindowsError( "CreatePipe" );
+ exit( EXITBAD );
+ }
+ if ( globs.pipe_action && !CreatePipe( &cmdtab[ slot ].pipe_err[
+ EXECCMD_PIPE_READ ], &cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_WRITE ],
+ &sa, 0 ) )
+ {
+ reportWindowsError( "CreatePipe" );
+ exit( EXITBAD );
+ }
+
+ /* Set handle inheritance off for the pipe ends the parent reads from. */
+ SetHandleInformation( cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_READ ],
+ HANDLE_FLAG_INHERIT, 0 );
+ if ( globs.pipe_action )
+ SetHandleInformation( cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_READ ],
+ HANDLE_FLAG_INHERIT, 0 );
+
+ /* Hide the child window, if any. */
+ si.dwFlags |= STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ /* Redirect the child's output streams to our pipes. */
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ si.hStdOutput = cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ];
+ si.hStdError = globs.pipe_action
+ ? cmdtab[ slot ].pipe_err[ EXECCMD_PIPE_WRITE ]
+ : cmdtab[ slot ].pipe_out[ EXECCMD_PIPE_WRITE ];
+
+ /* Let the child inherit stdin, as some commands assume it is available. */
+ si.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
+
+ /* Create output buffers. */
+ string_new( cmdtab[ slot ].buffer_out );
+ string_new( cmdtab[ slot ].buffer_err );
+
+ if ( DEBUG_EXECCMD )
+ printf( "Command string for CreateProcessA(): '%s'\n", command );
+
+ /* Run the command by creating a sub-process for it. */
+ if ( !CreateProcessA(
+ NULL , /* application name */
+ (char *)command , /* command line */
+ NULL , /* process attributes */
+ NULL , /* thread attributes */
+ TRUE , /* inherit handles */
+ CREATE_NEW_PROCESS_GROUP, /* create flags */
+ NULL , /* env vars, null inherits env */
+ NULL , /* current dir, null is our current dir */
+ &si , /* startup info */
+ &cmdtab[ slot ].pi ) ) /* child process info, if created */
+ {
+ reportWindowsError( "CreateProcessA" );
+ exit( EXITBAD );
+ }
 }
 
 
@@ -591,150 +507,106 @@
  * http://support.microsoft.com/default.aspx?scid=kb;en-us;830473
  */
 
-int maxline()
+static int raw_maxline()
 {
     OSVERSIONINFO os_info;
     os_info.dwOSVersionInfoSize = sizeof( os_info );
     GetVersionEx( &os_info );
 
- if ( os_info.dwMajorVersion >= 5 ) return 8191; /* XP > */
- if ( os_info.dwMajorVersion == 4 ) return 2047; /* NT 4.x */
- return 996; /* NT 3.5.1 */
+ if ( os_info.dwMajorVersion >= 5 ) return 8191; /* XP */
+ if ( os_info.dwMajorVersion == 4 ) return 2047; /* NT 4.x */
+ return 996; /* NT 3.5.1 */
+}
+
+static int maxline()
+{
+ static result;
+ if ( !result ) result = raw_maxline();
+ return result;
 }
 
 
 /*
- * Convert a command string into arguments for spawnvp(). The original code,
- * inherited from ftjam, tried to break up every argument on the command-line,
- * dealing with quotes, but that is really a waste of time on Win32, at least.
- * It turns out that all you need to do is get the raw path to the executable in
- * the first argument to spawnvp(), and you can pass all the rest of the
- * command-line arguments to spawnvp() in one, un-processed string.
- *
- * New strategy: break the string in at most one place.
+ * Closes a Windows HANDLE and resets its variable to 0.
  */
 
-static const char * * string_to_args( char const * string )
+static void closeWinHandle( HANDLE * const handle )
 {
- int src_len;
- int in_quote;
- char * line;
- char const * src;
- char * dst;
- const char * * argv;
-
- /* Drop leading and trailing whitespace if any. */
- while ( isspace( *string ) )
- ++string;
-
- src_len = strlen( string );
- while ( ( src_len > 0 ) && isspace( string[ src_len - 1 ] ) )
- --src_len;
-
- /* Copy the input string into a buffer we can modify. */
- line = (char *)BJAM_MALLOC_ATOMIC( src_len + 1 );
- if ( !line )
- return 0;
-
- /* Allocate the argv array.
- * element 0: stores the path to the executable
- * element 1: stores the command-line arguments to the executable
- * element 2: NULL terminator
- */
- argv = (const char * *)BJAM_MALLOC( 3 * sizeof( const char * ) );
- if ( !argv )
+ if ( *handle )
     {
- BJAM_FREE( line );
- return 0;
+ CloseHandle( *handle );
+ *handle = 0;
     }
-
- /* Strip quotes from the first command-line argument and find where it ends.
- * Quotes are illegal in Win32 pathnames, so we do not need to worry about
- * preserving escaped quotes here. Spaces can not be escaped in Win32, only
- * enclosed in quotes, so removing backslash escapes is also a non-issue.
- */
- in_quote = 0;
- for ( src = string, dst = line ; *src; ++src )
- {
- if ( *src == '"' )
- in_quote = !in_quote;
- else if ( !in_quote && isspace( *src ) )
- break;
- else
- *dst++ = *src;
- }
- *dst++ = 0;
- argv[ 0 ] = line;
-
- /* Skip whitespace in src. */
- while ( isspace( *src ) )
- ++src;
-
- argv[ 1 ] = dst;
-
- /* Copy the rest of the arguments verbatim. */
- src_len -= src - string;
-
- /* Use strncat() because it appends a trailing nul. */
- *dst = 0;
- strncat( dst, src, src_len );
-
- argv[ 2 ] = 0;
-
- return argv;
 }
 
 
-static void onintr( int disp )
+/*
+ * Frees and renews the given string.
+ */
+
+static void string_renew( string * const s )
 {
- ++intr;
- printf( "...interrupted\n" );
+ string_free( s );
+ string_new( s );
 }
 
 
 /*
- * can_spawn() - If the command is suitable for execution via spawnvp(), return
- * a number >= the number of characters it would occupy on the command-line.
- * Otherwise, return zero.
+ * raw_command_length() - valid raw command string length
+ *
+ * Checks whether the given command may be executed as a raw command. If yes,
+ * returns the corresponding command string length. If not, returns -1.
+ *
+ * Rules for constructing raw command strings:
+ * - Command may not contain unquoted shell I/O redirection characters.
+ * - May have at most one command line with non-whitespace content.
+ * - Leading whitespace trimmed.
+ * - Trailing all-whitespace lines trimmed.
+ * - Trailing whitespace on the sole command line kept (may theoretically
+ * affect the executed command).
  */
 
-long can_spawn( const char * command )
+static long raw_command_length( char const * command )
 {
- const char * p;
+ char const * p;
+ char const * escape = 0;
     char inquote = 0;
+ char const * newline = 0;
 
- /* Move to the first non-whitespace. */
- command += strspn( command, " \t" );
+ /* Skip leading whitespace. */
+ while ( isspace( *command ) )
+ ++command;
 
     p = command;
 
- /* Look for newlines and unquoted i/o redirection. */
+ /* Look for newlines and unquoted I/O redirection. */
     do
     {
- p += strcspn( p, "'\n\"<>|" );
-
+ p += strcspn( p, "\n\"'<>|\\" );
         switch ( *p )
         {
         case '\n':
- /* Skip over any following spaces. */
- while ( isspace( *p ) )
- ++p;
- /* Must use a .bat file if there is anything significant following
- * the newline.
+ /* If our command contains non-whitespace content split over
+ * multiple lines we can not execute it directly.
              */
- if ( *p )
- return 0;
+ newline = p;
+ while ( isspace( *++p ) );
+ if ( *p ) return -1;
+ break;
+
+ case '\\':
+ escape = escape && escape == p - 1 ? 0 : p;
+ ++p;
             break;
 
         case '"':
         case '\'':
- if ( ( p > command ) && ( p[ -1 ] != '\\' ) )
- {
- if ( inquote == *p )
- inquote = 0;
- else if ( inquote == 0 )
- inquote = *p;
- }
+ if ( escape && escape == p - 1 )
+ escape = 0;
+ else if ( inquote == *p )
+ inquote = 0;
+ else if ( !inquote )
+ inquote = *p;
             ++p;
             break;
 
@@ -742,7 +614,7 @@
         case '>':
         case '|':
             if ( !inquote )
- return 0;
+ return -1;
             ++p;
             break;
         }
@@ -750,16 +622,18 @@
     while ( *p );
 
     /* Return the number of characters the command will occupy. */
- return p - command;
+ return ( newline ? newline : p ) - command;
 }
 
 
 /* 64-bit arithmetic helpers. */
 
 /* Compute the carry bit from the addition of two 32-bit unsigned numbers. */
-#define add_carry_bit( a, b ) ( (((a) | (b)) >> 31) & (~((a) + (b)) >> 31) & 0x1 )
+#define add_carry_bit( a, b ) ((((a) | (b)) >> 31) & (~((a) + (b)) >> 31) & 0x1)
 
-/* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1 and h2l2. */
+/* Compute the high 32 bits of the addition of two 64-bit unsigned numbers, h1l1
+ * and h2l2.
+ */
 #define add_64_hi( h1, l1, h2, l2 ) ((h1) + (h2) + add_carry_bit(l1, l2))
 
 
@@ -795,49 +669,17 @@
 
 
 /*
- * Convert a FILETIME to a number of seconds.
+ * filetime_to_seconds() - Windows FILETIME --> number of seconds conversion
  */
 
-static double filetime_seconds( FILETIME t )
+static double filetime_to_seconds( FILETIME const ft )
 {
- return t.dwHighDateTime * ( (double)( 1UL << 31 ) * 2.0 * 1.0e-7 ) + t.dwLowDateTime * 1.0e-7;
+ return ft.dwHighDateTime * ( (double)( 1UL << 31 ) * 2.0 * 1.0e-7 ) +
+ ft.dwLowDateTime * 1.0e-7;
 }
 
 
-/*
- * What should be a simple conversion, turns out to be horribly complicated by
- * the defficiencies of MSVC and the Win32 API.
- */
-
-static time_t filetime_dt( FILETIME t_utc )
-{
- static int calc_time_diff = 1;
- static double time_diff;
- if ( calc_time_diff )
- {
- struct tm t0_;
- FILETIME f0_local;
- FILETIME f0_;
- SYSTEMTIME s0_;
- GetSystemTime( &s0_ );
- t0_.tm_year = s0_.wYear-1900;
- t0_.tm_mon = s0_.wMonth-1;
- t0_.tm_wday = s0_.wDayOfWeek;
- t0_.tm_mday = s0_.wDay;
- t0_.tm_hour = s0_.wHour;
- t0_.tm_min = s0_.wMinute;
- t0_.tm_sec = s0_.wSecond;
- t0_.tm_isdst = 0;
- SystemTimeToFileTime( &s0_, &f0_local );
- LocalFileTimeToFileTime( &f0_local, &f0_ );
- time_diff = filetime_seconds( f0_ ) - (double)mktime( &t0_ );
- calc_time_diff = 0;
- }
- return ceil( filetime_seconds( t_utc ) - time_diff );
-}
-
-
-static void record_times( HANDLE process, timing_info * time )
+static void record_times( HANDLE const process, timing_info * const time )
 {
     FILETIME creation;
     FILETIME exit;
@@ -845,10 +687,10 @@
     FILETIME user;
     if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
     {
- time->system = filetime_seconds( kernel );
- time->user = filetime_seconds( user );
- time->start = filetime_dt ( creation );
- time->end = filetime_dt ( exit );
+ time->system = filetime_to_seconds( kernel );
+ time->user = filetime_to_seconds( user );
+ timestamp_from_filetime( &time->start, &creation );
+ timestamp_from_filetime( &time->end, &exit );
     }
 }
 
@@ -870,16 +712,16 @@
     do
     {
         /* check if we have any data to read */
- if ( !PeekNamedPipe( in, ioBuffer, IO_BUFFER_SIZE, &bytesInBuffer, &bytesAvailable, NULL ) )
+ if ( !PeekNamedPipe( in, ioBuffer, IO_BUFFER_SIZE, &bytesInBuffer,
+ &bytesAvailable, NULL ) )
             bytesAvailable = 0;
 
         /* read in the available data */
         if ( bytesAvailable > 0 )
         {
             /* we only read in the available bytes, to avoid blocking */
- if ( ReadFile( in, ioBuffer,
- bytesAvailable <= IO_BUFFER_SIZE ? bytesAvailable : IO_BUFFER_SIZE,
- &bytesInBuffer, NULL ) )
+ if ( ReadFile( in, ioBuffer, bytesAvailable <= IO_BUFFER_SIZE ?
+ bytesAvailable : IO_BUFFER_SIZE, &bytesInBuffer, NULL ) )
             {
                 if ( bytesInBuffer > 0 )
                 {
@@ -917,15 +759,18 @@
 static void read_output()
 {
     int i;
- for ( i = 0; i < globs.jobs && i < MAXJOBS; ++i )
- {
- /* Read stdout data. */
- if ( cmdtab[ i ].pipe_out[ 0 ] )
- read_pipe( cmdtab[ i ].pipe_out[ 0 ], & cmdtab[ i ].buffer_out );
- /* Read stderr data. */
- if ( cmdtab[ i ].pipe_err[ 0 ] )
- read_pipe( cmdtab[ i ].pipe_err[ 0 ], & cmdtab[ i ].buffer_err );
- }
+ for ( i = 0; i < globs.jobs; ++i )
+ if ( cmdtab[ i ].pi.hProcess )
+ {
+ /* Read stdout data. */
+ if ( cmdtab[ i ].pipe_out[ EXECCMD_PIPE_READ ] )
+ read_pipe( cmdtab[ i ].pipe_out[ EXECCMD_PIPE_READ ],
+ cmdtab[ i ].buffer_out );
+ /* Read stderr data. */
+ if ( cmdtab[ i ].pipe_err[ EXECCMD_PIPE_READ ] )
+ read_pipe( cmdtab[ i ].pipe_err[ EXECCMD_PIPE_READ ],
+ cmdtab[ i ].buffer_err );
+ }
 }
 
 
@@ -935,7 +780,7 @@
  * cmdtab array, or -1.
  */
 
-static int try_wait( int timeoutMillis )
+static int try_wait( int const timeoutMillis )
 {
     int i;
     int num_active;
@@ -945,14 +790,12 @@
 
     /* Prepare a list of all active processes to wait for. */
     for ( num_active = 0, i = 0; i < globs.jobs; ++i )
- {
         if ( cmdtab[ i ].pi.hProcess )
         {
             active_handles[ num_active ] = cmdtab[ i ].pi.hProcess;
             active_procs[ num_active ] = i;
             ++num_active;
         }
- }
 
     /* Wait for a child to complete, or for our timeout window to expire. */
     wait_api_result = WaitForMultipleObjects( num_active, active_handles,
@@ -960,7 +803,7 @@
     if ( ( WAIT_OBJECT_0 <= wait_api_result ) &&
         ( wait_api_result < WAIT_OBJECT_0 + num_active ) )
     {
- /* Rerminated process detected - return its index. */
+ /* Terminated process detected - return its index. */
         return active_procs[ wait_api_result - WAIT_OBJECT_0 ];
     }
 
@@ -976,21 +819,22 @@
     {
         int i;
         for ( i = 0; i < globs.jobs; ++i )
- {
- double t = running_time( cmdtab[ i ].pi.hProcess );
- if ( t > (double)globs.timeout )
+ if ( cmdtab[ i ].pi.hProcess )
             {
- /* The job may have left an alert dialog around, try and get rid
- * of it before killing
- */
- close_alert( cmdtab[ i ].pi.hProcess );
- /* We have a "runaway" job, kill it. */
- kill_process_tree( 0, cmdtab[ i ].pi.hProcess );
- /* And return it marked as a timeout. */
- cmdtab[ i ].exit_reason = EXIT_TIMEOUT;
- return i;
+ double const t = running_time( cmdtab[ i ].pi.hProcess );
+ if ( t > (double)globs.timeout )
+ {
+ /* The job may have left an alert dialog around, try and get
+ * rid of it before killing the job itself.
+ */
+ close_alert( &cmdtab[ i ].pi );
+ /* We have a "runaway" job, kill it. */
+ kill_process_tree( cmdtab[ i ].pi.dwProcessId,
+ cmdtab[ i ].pi.hProcess );
+ /* And return its running commands table slot. */
+ return i;
+ }
             }
- }
     }
     return -1;
 }
@@ -998,7 +842,7 @@
 
 static void close_alerts()
 {
- /* We only attempt this every 5 seconds, or so, because it is not a cheap
+ /* We only attempt this every 5 seconds or so, because it is not a cheap
      * operation, and we will catch the alerts eventually. This check uses
      * floats as some compilers define CLOCKS_PER_SEC as a float or double.
      */
@@ -1006,7 +850,8 @@
     {
         int i;
         for ( i = 0; i < globs.jobs; ++i )
- close_alert( cmdtab[ i ].pi.hProcess );
+ if ( cmdtab[ i ].pi.hProcess )
+ close_alert( &cmdtab[ i ].pi );
     }
 }
 
@@ -1015,76 +860,33 @@
  * Calc the current running time of an *active* process.
  */
 
-static double running_time( HANDLE process )
+static double running_time( HANDLE const process )
 {
     FILETIME creation;
     FILETIME exit;
     FILETIME kernel;
     FILETIME user;
- FILETIME current;
     if ( GetProcessTimes( process, &creation, &exit, &kernel, &user ) )
     {
         /* Compute the elapsed time. */
+ FILETIME current;
         GetSystemTimeAsFileTime( &current );
- return filetime_seconds( add_FILETIME( current,
+ return filetime_to_seconds( add_FILETIME( current,
             negate_FILETIME( creation ) ) );
     }
     return 0.0;
 }
 
 
-/* It is just stupidly silly that one has to do this. */
-typedef struct PROCESS_BASIC_INFORMATION__
-{
- LONG ExitStatus;
- PVOID PebBaseAddress;
- ULONG AffinityMask;
- LONG BasePriority;
- ULONG UniqueProcessId;
- ULONG InheritedFromUniqueProcessId;
-} PROCESS_BASIC_INFORMATION_;
-typedef LONG (__stdcall * NtQueryInformationProcess__)(
- HANDLE ProcessHandle,
- LONG ProcessInformationClass,
- PVOID ProcessInformation,
- ULONG ProcessInformationLength,
- PULONG ReturnLength);
-static NtQueryInformationProcess__ NtQueryInformationProcess_ = NULL;
-static HMODULE NTDLL_ = NULL;
-DWORD get_process_id( HANDLE process )
-{
- PROCESS_BASIC_INFORMATION_ pinfo;
- if ( !NtQueryInformationProcess_ )
- {
- if ( ! NTDLL_ )
- NTDLL_ = GetModuleHandleA( "ntdll" );
- if ( NTDLL_ )
- NtQueryInformationProcess_
- = (NtQueryInformationProcess__)GetProcAddress( NTDLL_, "NtQueryInformationProcess" );
- }
- if ( NtQueryInformationProcess_ )
- {
- LONG r = (*NtQueryInformationProcess_)( process,
- /* ProcessBasicInformation == */ 0, &pinfo,
- sizeof( PROCESS_BASIC_INFORMATION_ ), NULL );
- return pinfo.UniqueProcessId;
- }
- return 0;
-}
-
-
 /*
  * Not really optimal, or efficient, but it is easier this way, and it is not
  * like we are going to be killing thousands, or even tens of processes.
  */
 
-static void kill_process_tree( DWORD pid, HANDLE process )
+static void kill_process_tree( DWORD const pid, HANDLE const process )
 {
- HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
- if ( !pid )
- pid = get_process_id( process );
- process_snapshot_h = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
-
+ HANDLE const process_snapshot_h = CreateToolhelp32Snapshot(
+ TH32CS_SNAPPROCESS, 0 );
     if ( INVALID_HANDLE_VALUE != process_snapshot_h )
     {
         BOOL ok = TRUE;
@@ -1099,9 +901,9 @@
             {
                 /* Found a child, recurse to kill it and anything else below it.
                  */
- HANDLE ph = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
+ HANDLE const ph = OpenProcess( PROCESS_ALL_ACCESS, FALSE,
                     pinfo.th32ProcessID );
- if ( NULL != ph )
+ if ( ph )
                 {
                     kill_process_tree( pinfo.th32ProcessID, ph );
                     CloseHandle( ph );
@@ -1115,15 +917,14 @@
 }
 
 
-static double creation_time( HANDLE process )
+static double creation_time( HANDLE const process )
 {
     FILETIME creation;
     FILETIME exit;
     FILETIME kernel;
     FILETIME user;
- FILETIME current;
     return GetProcessTimes( process, &creation, &exit, &kernel, &user )
- ? filetime_seconds( creation )
+ ? filetime_to_seconds( creation )
         : 0.0;
 }
 
@@ -1135,7 +936,7 @@
  * process is System (first argument is ignored).
  */
 
-static int is_parent_child( DWORD parent, DWORD child )
+static int is_parent_child( DWORD const parent, DWORD const child )
 {
     HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
 
@@ -1165,13 +966,14 @@
                  * reused by internals of the operating system when creating
                  * another process.
                  *
- * Thus additional check is needed - process creation time. This
- * check may fail (i.e. return 0) for system processes due to
- * insufficient privileges, and that is OK.
+ * Thus an additional check is needed - process creation time.
+ * This check may fail (i.e. return 0) for system processes due
+ * to insufficient privileges, and that is OK.
                  */
                 double tchild = 0.0;
                 double tparent = 0.0;
- HANDLE hchild = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pinfo.th32ProcessID );
+ HANDLE const hchild = OpenProcess( PROCESS_QUERY_INFORMATION,
+ FALSE, pinfo.th32ProcessID );
                 CloseHandle( process_snapshot_h );
 
                 /* csrss.exe may display message box like following:
@@ -1179,18 +981,18 @@
                  * This application has failed to start because
                  * boost_foo-bar.dll was not found. Re-installing the
                  * application may fix the problem
- * This actually happens when starting test process that depends
- * on a dynamic library which failed to build. We want to
- * automatically close these message boxes even though csrss.exe
- * is not our child process. We may depend on the fact that (in
- * all current versions of Windows) csrss.exe is directly child
- * of the smss.exe process, which in turn is directly child of
- * the System process, which always has process id == 4. This
- * check must be performed before comparison of process creation
- * times.
+ * This actually happens when starting a test process that
+ * depends on a dynamic library which failed to build. We want
+ * to automatically close these message boxes even though
+ * csrss.exe is not our child process. We may depend on the fact
+ * that (in all current versions of Windows) csrss.exe is a
+ * direct child of the smss.exe process, which in turn is a
+ * direct child of the System process, which always has process
+ * id == 4. This check must be performed before comparing
+ * process creation times.
                  */
                 if ( !stricmp( pinfo.szExeFile, "csrss.exe" ) &&
- ( is_parent_child( parent, pinfo.th32ParentProcessID ) == 2 ) )
+ is_parent_child( parent, pinfo.th32ParentProcessID ) == 2 )
                     return 1;
                 if ( !stricmp( pinfo.szExeFile, "smss.exe" ) &&
                     ( pinfo.th32ParentProcessID == 4 ) )
@@ -1227,76 +1029,203 @@
     return 0;
 }
 
-typedef struct PROCESS_HANDLE_ID { HANDLE h; DWORD pid; } PROCESS_HANDLE_ID;
-
 
 /*
- * This function is called by the operating system for each topmost window.
+ * Called by the OS for each topmost window.
  */
 
 BOOL CALLBACK close_alert_window_enum( HWND hwnd, LPARAM lParam )
 {
     char buf[ 7 ] = { 0 };
- PROCESS_HANDLE_ID p = *( (PROCESS_HANDLE_ID *)lParam );
- DWORD pid = 0;
- DWORD tid = 0;
+ PROCESS_INFORMATION const * const pi = (PROCESS_INFORMATION *)lParam;
+ DWORD pid;
+ DWORD tid;
 
     /* We want to find and close any window that:
      * 1. is visible and
      * 2. is a dialog and
      * 3. is displayed by any of our child processes
      */
- if ( !IsWindowVisible( hwnd ) )
+ if (
+ /* We assume hidden windows do not require user interaction. */
+ !IsWindowVisible( hwnd )
+ /* Failed to read class name; presume it is not a dialog. */
+ || !GetClassNameA( hwnd, buf, sizeof( buf ) )
+ /* All Windows system dialogs use the same Window class name. */
+ || strcmp( buf, "#32770" ) )
         return TRUE;
 
- if ( !GetClassNameA( hwnd, buf, sizeof( buf ) ) )
- return TRUE; /* Failed to read class name; presume it is not a dialog. */
-
- if ( strcmp( buf, "#32770" ) )
- return TRUE; /* Not a dialog */
-
     /* GetWindowThreadProcessId() returns 0 on error, otherwise thread id of
- * window message pump thread.
+ * the window's message pump thread.
      */
     tid = GetWindowThreadProcessId( hwnd, &pid );
+ if ( !tid || !is_parent_child( pi->dwProcessId, pid ) )
+ return TRUE;
+
+ /* Ask real nice. */
+ PostMessageA( hwnd, WM_CLOSE, 0, 0 );
+
+ /* Wait and see if it worked. If not, insist. */
+ if ( WaitForSingleObject( pi->hProcess, 200 ) == WAIT_TIMEOUT )
+ {
+ PostThreadMessageA( tid, WM_QUIT, 0, 0 );
+ WaitForSingleObject( pi->hProcess, 300 );
+ }
+
+ /* Done, we do not want to check any other windows now. */
+ return FALSE;
+}
+
+
+static void close_alert( PROCESS_INFORMATION const * const pi )
+{
+ EnumWindows( &close_alert_window_enum, (LPARAM)pi );
+}
+
+
+/*
+ * Open a command file to store the command into for executing using an external
+ * shell. Returns a pointer to a FILE open for writing or 0 in case such a file
+ * could not be opened. The file name used is stored back in the corresponding
+ * running commands table slot.
+ *
+ * Expects the running commands table slot's command_file attribute to contain
+ * either a zeroed out string object or one prepared previously by this same
+ * function.
+ */
+
+static FILE * open_command_file( int const slot )
+{
+ string * const command_file = cmdtab[ slot ].command_file;
 
- if ( tid && is_parent_child( p.pid, pid ) )
+ /* If the temporary command file name has not already been prepared for this
+ * slot number, prepare a new one containing a '##' place holder that will
+ * be changed later and needs to be located at a fixed distance from the
+ * end.
+ */
+ if ( !command_file->value )
+ {
+ DWORD const procID = GetCurrentProcessId();
+ string const * const tmpdir = path_tmpdir();
+ string_new( command_file );
+ string_reserve( command_file, tmpdir->size + 64 );
+ command_file->size = sprintf( command_file->value,
+ "%s\\jam%d-%02d-##.bat", tmpdir->value, procID, slot );
+ }
+
+ /* For some reason opening a command file can fail intermittently. But doing
+ * some retries works. Most likely this is due to a previously existing file
+ * of the same name that happens to still be opened by an active virus
+ * scanner. Originally pointed out and fixed by Bronek Kozicki.
+ *
+ * We first try to open several differently named files to avoid having to
+ * wait idly if not absolutely necessary. Our temporary command file names
+ * contain a fixed position place holder we use for generating different
+ * file names.
+ */
     {
- /* Ask really nice. */
- PostMessageA( hwnd, WM_CLOSE, 0, 0 );
- /* Now wait and see if it worked. If not, insist. */
- if ( WaitForSingleObject( p.h, 200 ) == WAIT_TIMEOUT )
+ char * const index1 = command_file->value + command_file->size - 6;
+ char * const index2 = index1 + 1;
+ int waits_remaining;
+ assert( command_file->value < index1 );
+ assert( index2 + 1 < command_file->value + command_file->size );
+ assert( index2[ 1 ] == '.' );
+ for ( waits_remaining = 3; ; --waits_remaining )
         {
- PostThreadMessageA( tid, WM_QUIT, 0, 0 );
- WaitForSingleObject( p.h, 300 );
+ int index;
+ for ( index = 0; index != 20; ++index )
+ {
+ FILE * f;
+ *index1 = '0' + index / 10;
+ *index2 = '0' + index % 10;
+ f = fopen( command_file->value, "w" );
+ if ( f ) return f;
+ }
+ if ( !waits_remaining ) break;
+ Sleep( 250 );
         }
+ }
+
+ return 0;
+}
 
- /* Done, we do not want to check any other window now. */
- return FALSE;
+
+/*
+ * Prepare a command file to be executed using an external shell.
+ */
+
+static char const * prepare_command_file( string const * command, int slot )
+{
+ FILE * const f = open_command_file( slot );
+ if ( !f )
+ {
+ printf( "failed to write command file!\n" );
+ exit( EXITBAD );
     }
+ fputs( command->value, f );
+ fclose( f );
+ return cmdtab[ slot ].command_file->value;
+}
 
- return TRUE;
+
+/*
+ * Find a free slot in the running commands table.
+ */
+
+static int get_free_cmdtab_slot()
+{
+ int slot;
+ for ( slot = 0; slot < MAXJOBS; ++slot )
+ if ( !cmdtab[ slot ].pi.hProcess )
+ return slot;
+ printf( "no slots for child!\n" );
+ exit( EXITBAD );
 }
 
 
-static void close_alert( HANDLE process )
+/*
+ * Put together the final command string we are to run.
+ */
+
+static void string_new_from_argv( string * result, char const * const * argv )
 {
- DWORD pid = get_process_id( process );
- /* If process already exited or we just can not get its process id, do not
- * go any further.
- */
- if ( pid )
+ assert( argv );
+ assert( argv[ 0 ] );
+ string_copy( result, *(argv++) );
+ while ( *argv )
     {
- PROCESS_HANDLE_ID p;
- p.h = process;
- p.pid = pid;
- EnumWindows( &close_alert_window_enum, (LPARAM)&p );
+ string_push_back( result, ' ' );
+ string_append( result, *(argv++) );
     }
 }
 
 
-void exec_done( void )
+/*
+ * Reports the last failed Windows API related error message.
+ */
+
+static void reportWindowsError( char const * const apiName )
 {
+ char * errorMessage;
+ DWORD const errorCode = GetLastError();
+ DWORD apiResult = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | /* __in DWORD dwFlags */
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, /* __in_opt LPCVOID lpSource */
+ errorCode, /* __in DWORD dwMessageId */
+ 0, /* __in DWORD dwLanguageId */
+ (LPSTR)&errorMessage, /* __out LPTSTR lpBuffer */
+ 0, /* __in DWORD nSize */
+ 0 ); /* __in_opt va_list * Arguments */
+ if ( !apiResult )
+ printf( "%s() Windows API failed: %d.\n", apiName, errorCode );
+ else
+ {
+ printf( "%s() Windows API failed: %d - %s\n", apiName, errorCode,
+ errorMessage );
+ LocalFree( errorMessage );
+ }
 }
 
 

Modified: branches/release/tools/build/v2/engine/execunix.c
==============================================================================
--- branches/release/tools/build/v2/engine/execunix.c (original)
+++ branches/release/tools/build/v2/engine/execunix.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,19 +6,22 @@
  */
 
 #include "jam.h"
-#include "lists.h"
 #include "execcmd.h"
+
+#include "lists.h"
 #include "output.h"
+#include "strings.h"
+
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
 #include <time.h>
-#include <unistd.h> /* needed for vfork(), _exit() prototypes */
+#include <unistd.h> /* vfork(), _exit(), STDOUT_FILENO and such */
 #include <sys/resource.h>
 #include <sys/times.h>
 #include <sys/wait.h>
 
-#if defined(sun) || defined(__sun) || defined(linux)
+#if defined(sun) || defined(__sun)
     #include <wait.h>
 #endif
 
@@ -36,71 +39,83 @@
 
 
 /*
- * execunix.c - execute a shell script on UNIX/WinNT/OS2/AmigaOS
+ * execunix.c - execute a shell script on UNIX/OS2/AmigaOS
  *
- * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp().
- * The default is:
- *
- * /bin/sh -c % [ on UNIX/AmigaOS ]
- * cmd.exe /c % [ on OS2/WinNT ]
- *
- * Each word must be an individual element in a jam variable value.
+ * If $(JAMSHELL) is defined, uses that to formulate execvp()/spawnvp(). The
+ * default is: /bin/sh -c
  *
  * In $(JAMSHELL), % expands to the command string and ! expands to the slot
  * number (starting at 1) for multiprocess (-j) invocations. If $(JAMSHELL) does
  * not include a %, it is tacked on as the last argument.
  *
- * Do not just set JAMSHELL to /bin/sh or cmd.exe - it will not work!
+ * Each word must be an individual element in a jam variable value.
+ *
+ * Do not just set JAMSHELL to /bin/sh - it will not work!
  *
  * External routines:
+ * exec_check() - preprocess and validate the command.
  * exec_cmd() - launch an async command execution.
- * exec_wait() - wait and drive at most one execution completion.
- *
- * Internal routines:
- * onintr() - bump intr to note command interruption.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 05/04/94 (seiwald) - async multiprocess interface
- * 01/22/95 (seiwald) - $(JAMSHELL) support
- * 06/02/97 (gsar) - full async multiprocess support for Win32
+ * exec_wait() - wait for any of the async command processes to terminate.
  */
 
-static clock_t tps = 0;
-static struct timeval tv;
-static int select_timeout = 0;
-static int intr = 0;
-static int cmdsrunning = 0;
+/* find a free slot in the running commands table */
+static int get_free_cmdtab_slot();
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static clock_t tps;
+static int old_time_initialized;
 static struct tms old_time;
 
+/* We hold stdout & stderr child process information in two element arrays
+ * indexed as follows.
+ */
 #define OUT 0
 #define ERR 1
 
 static struct
 {
- int pid; /* on win32, a real process handle */
- int fd[2]; /* file descriptors for stdout and stderr */
- FILE *stream[2]; /* child's stdout (0) and stderr (1) file stream */
- clock_t start_time; /* start time of child process */
- int exit_reason; /* termination status */
- int action_length; /* length of action string */
- int target_length; /* length of target string */
- char *action; /* buffer to hold action and target invoked */
- char *target; /* buffer to hold action and target invoked */
- char *command; /* buffer to hold command being invoked */
- char *buffer[2]; /* buffer to hold stdout and stderr, if any */
- void (*func)( void *closure, int status, timing_info*, const char *, const char * );
- void *closure;
- time_t start_dt; /* start of command timestamp */
-} cmdtab[ MAXJOBS ] = {{0}};
+ int pid; /* on win32, a real process handle */
+ int fd[ 2 ]; /* file descriptors for stdout and stderr */
+ FILE * stream[ 2 ]; /* child's stdout and stderr file streams */
+ clock_t start_time; /* start time of child process */
+ int exit_reason; /* termination status */
+ char * buffer[ 2 ]; /* buffers to hold stdout and stderr, if any */
+ int buf_size[ 2 ]; /* buffer sizes in bytes */
+ timestamp start_dt; /* start of command timestamp */
+
+ /* Function called when the command completes. */
+ ExecCmdCallback func;
+
+ /* Opaque data passed back to the 'func' callback. */
+ void * closure;
+} cmdtab[ MAXJOBS ] = { { 0 } };
+
 
 /*
- * onintr() - bump intr to note command interruption
+ * exec_check() - preprocess and validate the command.
  */
 
-void onintr( int disp )
+int exec_check
+(
+ string const * command,
+ LIST * * pShell,
+ int * error_length,
+ int * error_max_length
+)
 {
- ++intr;
- printf( "...interrupted\n" );
+ int const is_raw_cmd = is_raw_command_request( *pShell );
+
+ /* We allow empty commands for non-default shells since we do not really
+ * know what they are going to do with such commands.
+ */
+ if ( !command->size && ( is_raw_cmd || list_empty( *pShell ) ) )
+ return EXEC_CHECK_NOOP;
+
+ return is_raw_cmd
+ ? EXEC_CHECK_OK
+ : check_cmd_for_too_long_lines( command->value, MAXLINE, error_length,
+ error_max_length );
 }
 
 
@@ -108,131 +123,110 @@
  * exec_cmd() - launch an async command execution.
  */
 
+/* We hold file descriptors for pipes used to communicate with child processes
+ * in two element arrays indexed as follows.
+ */
+#define EXECCMD_PIPE_READ 0
+#define EXECCMD_PIPE_WRITE 1
+
 void exec_cmd
 (
- const char * string,
- void (*func)( void *closure, int status, timing_info*, const char *, const char * ),
+ string const * command,
+ ExecCmdCallback func,
     void * closure,
- LIST * shell,
- const char * action,
- const char * target
+ LIST * shell
 )
 {
- static int initialized = 0;
- int out[2];
- int err[2];
- int slot;
- int len;
- const char * argv[ MAXARGC + 1 ]; /* +1 for NULL */
-
- /* Find a slot in the running commands table for this one. */
- for ( slot = 0; slot < MAXJOBS; ++slot )
- if ( !cmdtab[ slot ].pid )
- break;
+ int const slot = get_free_cmdtab_slot();
+ int out[ 2 ];
+ int err[ 2 ];
+ int len;
+ char const * argv[ MAXARGC + 1 ]; /* +1 for NULL */
+
+ /* Initialize default shell. */
+ static LIST * default_shell;
+ if ( !default_shell )
+ default_shell = list_push_back( list_new(
+ object_new( "/bin/sh" ) ),
+ object_new( "-c" ) );
 
- if ( slot == MAXJOBS )
- {
- printf( "no slots for child!\n" );
- exit( EXITBAD );
- }
+ if ( list_empty( shell ) )
+ shell = default_shell;
 
     /* Forumulate argv. If shell was defined, be prepared for % and ! subs.
- * Otherwise, use stock /bin/sh on unix or cmd.exe on NT.
+ * Otherwise, use stock /bin/sh.
      */
- if ( !list_empty( shell ) )
- {
- int i;
- char jobno[4];
- int gotpercent = 0;
- LISTITER iter = list_begin( shell ), end = list_end( shell );
-
- sprintf( jobno, "%d", slot + 1 );
+ argv_from_shell( argv, shell, command->value, slot );
 
- for ( i = 0; iter != end && i < MAXARGC; ++i, iter = list_next( iter ) )
- {
- switch ( object_str( list_item( iter ) )[0] )
- {
- case '%': argv[ i ] = string; ++gotpercent; break;
- case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = object_str( list_item( iter ) );
- }
- if ( DEBUG_EXECCMD )
- printf( "argv[%d] = '%s'\n", i, argv[ i ] );
- }
-
- if ( !gotpercent )
- argv[ i++ ] = string;
-
- argv[ i ] = 0;
- }
- else
+ if ( DEBUG_EXECCMD )
     {
- argv[ 0 ] = "/bin/sh";
- argv[ 1 ] = "-c";
- argv[ 2 ] = string;
- argv[ 3 ] = 0;
+ int i;
+ printf( "Using shell: " );
+ list_print( shell );
+ printf( "\n" );
+ for ( i = 0; argv[ i ]; ++i )
+ printf( " argv[%d] = '%s'\n", i, argv[ i ] );
     }
 
- /* Increment jobs running. */
- ++cmdsrunning;
-
- /* Save off actual command string. */
- cmdtab[ slot ].command = BJAM_MALLOC_ATOMIC( strlen( string ) + 1 );
- strcpy( cmdtab[ slot ].command, string );
-
- /* Initialize only once. */
- if ( !initialized )
+ /* Create pipes for collecting child output. */
+ if ( pipe( out ) < 0 || ( globs.pipe_action && pipe( err ) < 0 ) )
     {
- times( &old_time );
- initialized = 1;
+ perror( "pipe" );
+ exit( EXITBAD );
     }
 
- /* Create pipes from child to parent. */
+ /* Initialize old_time only once. */
+ if ( !old_time_initialized )
     {
- if ( pipe( out ) < 0 )
- exit( EXITBAD );
-
- if ( pipe( err ) < 0 )
- exit( EXITBAD );
+ times( &old_time );
+ old_time_initialized = 1;
     }
 
     /* Start the command */
 
- cmdtab[ slot ].start_dt = time(0);
+ timestamp_current( &cmdtab[ slot ].start_dt );
 
     if ( 0 < globs.timeout )
     {
- /*
- * Handle hung processes by manually tracking elapsed time and signal
+ /* Handle hung processes by manually tracking elapsed time and signal
          * process when time limit expires.
          */
         struct tms buf;
         cmdtab[ slot ].start_time = times( &buf );
 
         /* Make a global, only do this once. */
- if ( tps == 0 ) tps = sysconf( _SC_CLK_TCK );
+ if ( !tps ) tps = sysconf( _SC_CLK_TCK );
     }
 
- if ( ( cmdtab[ slot ].pid = vfork() ) == 0 )
- {
- int pid = getpid();
-
- close( out[0] );
- close( err[0] );
-
- dup2( out[1], STDOUT_FILENO );
+ /* Child does not need the read pipe ends used by the parent. */
+ fcntl( out[ EXECCMD_PIPE_READ ], F_SETFD, FD_CLOEXEC );
+ if ( globs.pipe_action )
+ fcntl( err[ EXECCMD_PIPE_READ ], F_SETFD, FD_CLOEXEC );
 
- if ( globs.pipe_action == 0 )
- dup2( out[1], STDERR_FILENO );
- else
- dup2( err[1], STDERR_FILENO );
+ if ( ( cmdtab[ slot ].pid = vfork() ) == -1 )
+ {
+ perror( "vfork" );
+ exit( EXITBAD );
+ }
 
- close( out[1] );
- close( err[1] );
+ if ( cmdtab[ slot ].pid == 0 )
+ {
+ /*****************/
+ /* Child process */
+ /*****************/
+ int const pid = getpid();
+
+ /* Redirect stdout and stderr to pipes inherited from the parent. */
+ dup2( out[ EXECCMD_PIPE_WRITE ], STDOUT_FILENO );
+ dup2( globs.pipe_action ? err[ EXECCMD_PIPE_WRITE ] :
+ out[ EXECCMD_PIPE_WRITE ], STDERR_FILENO );
+ close( out[ EXECCMD_PIPE_WRITE ] );
+ if ( globs.pipe_action )
+ close( err[ EXECCMD_PIPE_WRITE ] );
 
         /* Make this process a process group leader so that when we kill it, all
          * child processes of this process are terminated as well. We use
- * killpg(pid, SIGKILL) to kill the process group leader and all its
+ * killpg( pid, SIGKILL ) to kill the process group leader and all its
          * children.
          */
         if ( 0 < globs.timeout )
@@ -242,96 +236,58 @@
             r_limit.rlim_max = globs.timeout;
             setrlimit( RLIMIT_CPU, &r_limit );
         }
- setpgid( pid,pid );
- execvp( argv[0], (char * *)argv );
+ setpgid( pid, pid );
+ execvp( argv[ 0 ], (char * *)argv );
         perror( "execvp" );
         _exit( 127 );
     }
- else if ( cmdtab[ slot ].pid == -1 )
- {
- perror( "vfork" );
- exit( EXITBAD );
- }
 
+ /******************/
+ /* Parent process */
+ /******************/
     setpgid( cmdtab[ slot ].pid, cmdtab[ slot ].pid );
 
- /* close write end of pipes */
- close( out[1] );
- close( err[1] );
-
- /* set both file descriptors to non-blocking */
- fcntl(out[0], F_SETFL, O_NONBLOCK);
- fcntl(err[0], F_SETFL, O_NONBLOCK);
+ /* Parent not need the write pipe ends used by the child. */
+ close( out[ EXECCMD_PIPE_WRITE ] );
+ if ( globs.pipe_action )
+ close( err[ EXECCMD_PIPE_WRITE ] );
+
+ /* Set both pipe read file descriptors to non-blocking. */
+ fcntl( out[ EXECCMD_PIPE_READ ], F_SETFL, O_NONBLOCK );
+ if ( globs.pipe_action )
+ fcntl( err[ EXECCMD_PIPE_READ ], F_SETFL, O_NONBLOCK );
 
- /* child writes stdout to out[1], parent reads from out[0] */
- cmdtab[ slot ].fd[ OUT ] = out[0];
+ /* Parent reads from out[ EXECCMD_PIPE_READ ]. */
+ cmdtab[ slot ].fd[ OUT ] = out[ EXECCMD_PIPE_READ ];
     cmdtab[ slot ].stream[ OUT ] = fdopen( cmdtab[ slot ].fd[ OUT ], "rb" );
- if ( cmdtab[ slot ].stream[ OUT ] == NULL )
+ if ( !cmdtab[ slot ].stream[ OUT ] )
     {
         perror( "fdopen" );
         exit( EXITBAD );
     }
 
- /* child writes stderr to err[1], parent reads from err[0] */
- if (globs.pipe_action == 0)
- {
- close(err[0]);
- }
- else
+ /* Parent reads from err[ EXECCMD_PIPE_READ ]. */
+ if ( globs.pipe_action )
     {
- cmdtab[ slot ].fd[ ERR ] = err[0];
+ cmdtab[ slot ].fd[ ERR ] = err[ EXECCMD_PIPE_READ ];
         cmdtab[ slot ].stream[ ERR ] = fdopen( cmdtab[ slot ].fd[ ERR ], "rb" );
- if ( cmdtab[ slot ].stream[ ERR ] == NULL )
+ if ( !cmdtab[ slot ].stream[ ERR ] )
         {
             perror( "fdopen" );
             exit( EXITBAD );
         }
     }
 
- /* Ensure enough room for rule and target name. */
- if ( action && target )
- {
- len = strlen( action ) + 1;
- if ( cmdtab[ slot ].action_length < len )
- {
- BJAM_FREE( cmdtab[ slot ].action );
- cmdtab[ slot ].action = BJAM_MALLOC_ATOMIC( len );
- cmdtab[ slot ].action_length = len;
- }
- strcpy( cmdtab[ slot ].action, action );
- len = strlen( target ) + 1;
- if ( cmdtab[ slot ].target_length < len )
- {
- BJAM_FREE( cmdtab[ slot ].target );
- cmdtab[ slot ].target = BJAM_MALLOC_ATOMIC( len );
- cmdtab[ slot ].target_length = len;
- }
- strcpy( cmdtab[ slot ].target, target );
- }
- else
- {
- BJAM_FREE( cmdtab[ slot ].action );
- BJAM_FREE( cmdtab[ slot ].target );
- cmdtab[ slot ].action = 0;
- cmdtab[ slot ].target = 0;
- cmdtab[ slot ].action_length = 0;
- cmdtab[ slot ].target_length = 0;
- }
-
- /* Save the operation for exec_wait() to find. */
+ /* Save input data into the selected running commands table slot. */
     cmdtab[ slot ].func = func;
     cmdtab[ slot ].closure = closure;
-
- /* Wait until we are under the limit of concurrent commands. Do not trust
- * globs.jobs alone.
- */
- while ( ( cmdsrunning >= MAXJOBS ) || ( cmdsrunning >= globs.jobs ) )
- if ( !exec_wait() )
- break;
 }
 
+#undef EXECCMD_PIPE_READ
+#undef EXECCMD_PIPE_WRITE
 
-/* Returns 1 if file is closed, 0 if descriptor is still live.
+
+/* Returns 1 if file descriptor is closed, or 0 if it is still alive.
  *
  * i is index into cmdtab
  *
@@ -341,241 +297,263 @@
  * - cmdtab[ i ].fd [ s ]
  */
 
-int read_descriptor( int i, int s )
+static int read_descriptor( int i, int s )
 {
- int ret;
- int len;
- char buffer[BUFSIZ];
+ int ret;
+ char buffer[ BUFSIZ ];
 
- while ( 0 < ( ret = fread( buffer, sizeof(char), BUFSIZ-1, cmdtab[ i ].stream[ s ] ) ) )
+ while ( 0 < ( ret = fread( buffer, sizeof( char ), BUFSIZ - 1,
+ cmdtab[ i ].stream[ s ] ) ) )
     {
- buffer[ret] = 0;
- if ( !cmdtab[ i ].buffer[ s ] )
+ buffer[ ret ] = 0;
+ if ( !cmdtab[ i ].buffer[ s ] )
         {
             /* Never been allocated. */
+ if ( globs.max_buf && ret > globs.max_buf )
+ {
+ ret = globs.max_buf;
+ buffer[ ret ] = 0;
+ }
+ cmdtab[ i ].buf_size[ s ] = ret + 1;
             cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( ret + 1 );
             memcpy( cmdtab[ i ].buffer[ s ], buffer, ret + 1 );
         }
         else
         {
             /* Previously allocated. */
- char * tmp = cmdtab[ i ].buffer[ s ];
- len = strlen( tmp );
- cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( len + ret + 1 );
- memcpy( cmdtab[ i ].buffer[ s ], tmp, len );
- memcpy( cmdtab[ i ].buffer[ s ] + len, buffer, ret + 1 );
- BJAM_FREE( tmp );
+ if ( cmdtab[ i ].buf_size[ s ] < globs.max_buf || !globs.max_buf )
+ {
+ char * tmp = cmdtab[ i ].buffer[ s ];
+ int const old_len = cmdtab[ i ].buf_size[ s ] - 1;
+ int const new_len = old_len + ret + 1;
+ cmdtab[ i ].buf_size[ s ] = new_len;
+ cmdtab[ i ].buffer[ s ] = (char*)BJAM_MALLOC_ATOMIC( new_len );
+ memcpy( cmdtab[ i ].buffer[ s ], tmp, old_len );
+ memcpy( cmdtab[ i ].buffer[ s ] + old_len, buffer, ret + 1 );
+ BJAM_FREE( tmp );
+ }
         }
     }
 
- return feof(cmdtab[ i ].stream[ s ]);
+ /* If buffer full, ensure last buffer char is newline so that jam log
+ * contains the command status at beginning of it own line instead of
+ * appended to end of the previous output.
+ */
+ if ( globs.max_buf && globs.max_buf <= cmdtab[ i ].buf_size[ s ] )
+ cmdtab[ i ].buffer[ s ][ cmdtab[ i ].buf_size[ s ] - 2 ] = '\n';
+
+ return feof( cmdtab[ i ].stream[ s ] );
 }
 
 
-void close_streams( int i, int s )
+/*
+ * close_streams() - Close the stream and pipe descriptor.
+ */
+
+static void close_streams( int const i, int const s )
 {
- /* Close the stream and pipe descriptor. */
- fclose(cmdtab[ i ].stream[ s ]);
+ fclose( cmdtab[ i ].stream[ s ] );
     cmdtab[ i ].stream[ s ] = 0;
 
- close(cmdtab[ i ].fd[ s ]);
+ close( cmdtab[ i ].fd[ s ] );
     cmdtab[ i ].fd[ s ] = 0;
 }
 
 
-void populate_file_descriptors( int * fmax, fd_set * fds)
+/*
+ * Populate the file descriptors collection for use in select() and return the
+ * maximal included file descriptor value.
+ */
+
+static int populate_file_descriptors( fd_set * const fds )
 {
- int i, fd_max = 0;
- struct tms buf;
- clock_t current = times( &buf );
- select_timeout = globs.timeout;
+ int i;
+ int fd_max = 0;
 
- /* Compute max read file descriptor for use in select. */
- FD_ZERO(fds);
+ FD_ZERO( fds );
     for ( i = 0; i < globs.jobs; ++i )
     {
- if ( 0 < cmdtab[ i ].fd[ OUT ] )
+ int fd;
+ if ( ( fd = cmdtab[ i ].fd[ OUT ] ) > 0 )
         {
- fd_max = fd_max < cmdtab[ i ].fd[ OUT ] ? cmdtab[ i ].fd[ OUT ] : fd_max;
- FD_SET(cmdtab[ i ].fd[ OUT ], fds);
+ if ( fd > fd_max ) fd_max = fd;
+ FD_SET( fd, fds );
         }
- if ( globs.pipe_action != 0 )
+ if ( globs.pipe_action )
         {
- if (0 < cmdtab[ i ].fd[ ERR ])
+ if ( ( fd = cmdtab[ i ].fd[ ERR ] ) > 0 )
             {
- fd_max = fd_max < cmdtab[ i ].fd[ ERR ] ? cmdtab[ i ].fd[ ERR ] : fd_max;
- FD_SET(cmdtab[ i ].fd[ ERR ], fds);
- }
- }
-
- if (globs.timeout && cmdtab[ i ].pid) {
- clock_t consumed = (current - cmdtab[ i ].start_time) / tps;
- clock_t process_timesout = globs.timeout - consumed;
- if (0 < process_timesout && process_timesout < select_timeout) {
- select_timeout = process_timesout;
- }
- if ( globs.timeout <= consumed )
- {
- killpg( cmdtab[ i ].pid, SIGKILL );
- cmdtab[ i ].exit_reason = EXIT_TIMEOUT;
+ if ( fd > fd_max ) fd_max = fd;
+ FD_SET( fd, fds );
             }
         }
     }
- *fmax = fd_max;
+ return fd_max;
 }
 
 
 /*
- * exec_wait() - wait and drive at most one execution completion.
+ * exec_wait() - wait for any of the async command processes to terminate.
+ *
+ * May register more than one terminated child process but will exit as soon as
+ * at least one has been registered.
  */
 
-int exec_wait()
+void exec_wait()
 {
- int i;
- int ret;
- int fd_max;
- int pid;
- int status;
- int finished;
- int rstat;
- timing_info time_info;
- fd_set fds;
- struct tms new_time;
-
- /* Handle naive make1() which does not know if commands are running. */
- if ( !cmdsrunning )
- return 0;
+ int finished = 0;
 
     /* Process children that signaled. */
- finished = 0;
- while ( !finished && cmdsrunning )
+ while ( !finished )
     {
- /* Compute max read file descriptor for use in select(). */
- populate_file_descriptors( &fd_max, &fds );
-
- if ( 0 < globs.timeout )
+ int i;
+ struct timeval tv;
+ struct timeval * ptv = NULL;
+ int select_timeout = globs.timeout;
+
+ /* Prepare file descriptor information for use in select(). */
+ fd_set fds;
+ int const fd_max = populate_file_descriptors( &fds );
+
+ /* Check for timeouts:
+ * - kill children that already timed out
+ * - decide how long until the next one times out
+ */
+ if ( globs.timeout > 0 )
         {
- /* Force select() to timeout so we can terminate expired processes.
+ struct tms buf;
+ clock_t const current = times( &buf );
+ for ( i = 0; i < globs.jobs; ++i )
+ if ( cmdtab[ i ].pid )
+ {
+ clock_t const consumed =
+ ( current - cmdtab[ i ].start_time ) / tps;
+ if ( consumed >= globs.timeout )
+ {
+ killpg( cmdtab[ i ].pid, SIGKILL );
+ cmdtab[ i ].exit_reason = EXIT_TIMEOUT;
+ }
+ else if ( globs.timeout - consumed < select_timeout )
+ select_timeout = globs.timeout - consumed;
+ }
+
+ /* If nothing else causes our select() call to exit, force it after
+ * however long it takes for the next one of our child processes to
+ * crossed its alloted processing time so we can terminate it.
              */
             tv.tv_sec = select_timeout;
             tv.tv_usec = 0;
-
- /* select() will wait until: i/o on a descriptor, a signal, or we
- * time out.
- */
- ret = select( fd_max + 1, &fds, 0, 0, &tv );
+ ptv = &tv;
         }
- else
+
+ /* select() will wait for I/O on a descriptor, a signal, or timeout. */
         {
- /* select() will wait until i/o on a descriptor or a signal. */
- ret = select( fd_max + 1, &fds, 0, 0, 0 );
+ int ret;
+ while ( ( ret = select( fd_max + 1, &fds, 0, 0, ptv ) ) == -1 )
+ if ( errno != EINTR )
+ break;
+ if ( ret <= 0 )
+ continue;
         }
 
- if ( 0 < ret )
+ for ( i = 0; i < globs.jobs; ++i )
         {
- for ( i = 0; i < globs.jobs; ++i )
- {
- int out = 0;
- int err = 0;
- if ( FD_ISSET( cmdtab[ i ].fd[ OUT ], &fds ) )
- out = read_descriptor( i, OUT );
-
- if ( ( globs.pipe_action != 0 ) &&
- ( FD_ISSET( cmdtab[ i ].fd[ ERR ], &fds ) ) )
- err = read_descriptor( i, ERR );
+ int out_done = 0;
+ int err_done = 0;
+ if ( FD_ISSET( cmdtab[ i ].fd[ OUT ], &fds ) )
+ out_done = read_descriptor( i, OUT );
 
- /* If feof on either descriptor, then we are done. */
- if ( out || err )
+ if ( globs.pipe_action && FD_ISSET( cmdtab[ i ].fd[ ERR ], &fds ) )
+ err_done = read_descriptor( i, ERR );
+
+ /* If feof on either descriptor, we are done. */
+ if ( out_done || err_done )
+ {
+ int pid;
+ int status;
+ int rstat;
+ timing_info time_info;
+
+ /* We found a terminated child process - our search is done. */
+ finished = 1;
+
+ /* Close the stream and pipe descriptors. */
+ close_streams( i, OUT );
+ if ( globs.pipe_action )
+ close_streams( i, ERR );
+
+ /* Reap the child and release resources. */
+ while ( ( pid = waitpid( cmdtab[ i ].pid, &status, 0 ) ) == -1 )
+ if ( errno != EINTR )
+ break;
+ if ( pid != cmdtab[ i ].pid )
                 {
- /* Close the stream and pipe descriptors. */
- close_streams( i, OUT );
- if ( globs.pipe_action != 0 )
- close_streams( i, ERR );
+ printf( "unknown pid %d with errno = %d\n", pid, errno );
+ exit( EXITBAD );
+ }
 
- /* Reap the child and release resources. */
- pid = waitpid( cmdtab[ i ].pid, &status, 0 );
+ /* Set reason for exit if not timed out. */
+ if ( WIFEXITED( status ) )
+ cmdtab[ i ].exit_reason = WEXITSTATUS( status )
+ ? EXIT_FAIL
+ : EXIT_OK;
 
- if ( pid == cmdtab[ i ].pid )
- {
- finished = 1;
- pid = 0;
- cmdtab[ i ].pid = 0;
-
- /* Set reason for exit if not timed out. */
- if ( WIFEXITED( status ) )
- {
- cmdtab[ i ].exit_reason = 0 == WEXITSTATUS( status )
- ? EXIT_OK
- : EXIT_FAIL;
- }
-
- /* Print out the rule and target name. */
- out_action( cmdtab[ i ].action, cmdtab[ i ].target,
- cmdtab[ i ].command, cmdtab[ i ].buffer[ OUT ],
- cmdtab[ i ].buffer[ ERR ], cmdtab[ i ].exit_reason
- );
-
- times( &new_time );
-
- time_info.system = (double)( new_time.tms_cstime - old_time.tms_cstime ) / CLOCKS_PER_SEC;
- time_info.user = (double)( new_time.tms_cutime - old_time.tms_cutime ) / CLOCKS_PER_SEC;
- time_info.start = cmdtab[ i ].start_dt;
- time_info.end = time( 0 );
-
- old_time = new_time;
-
- /* Drive the completion. */
- --cmdsrunning;
-
- if ( intr )
- rstat = EXEC_CMD_INTR;
- else if ( status != 0 )
- rstat = EXEC_CMD_FAIL;
- else
- rstat = EXEC_CMD_OK;
-
- /* Assume -p0 in effect so only pass buffer[ 0 ]
- * containing merged output.
- */
- (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat,
- &time_info, cmdtab[ i ].command,
- cmdtab[ i ].buffer[ 0 ] );
-
- BJAM_FREE( cmdtab[ i ].buffer[ OUT ] );
- cmdtab[ i ].buffer[ OUT ] = 0;
-
- BJAM_FREE( cmdtab[ i ].buffer[ ERR ] );
- cmdtab[ i ].buffer[ ERR ] = 0;
-
- BJAM_FREE( cmdtab[ i ].command );
- cmdtab[ i ].command = 0;
-
- cmdtab[ i ].func = 0;
- cmdtab[ i ].closure = 0;
- cmdtab[ i ].start_time = 0;
- }
- else
- {
- printf( "unknown pid %d with errno = %d\n", pid, errno );
- exit( EXITBAD );
- }
+ {
+ struct tms new_time;
+ times( &new_time );
+ time_info.system = (double)( new_time.tms_cstime -
+ old_time.tms_cstime ) / CLOCKS_PER_SEC;
+ time_info.user = (double)( new_time.tms_cutime -
+ old_time.tms_cutime ) / CLOCKS_PER_SEC;
+ timestamp_copy( &time_info.start, &cmdtab[ i ].start_dt );
+ timestamp_current( &time_info.end );
+ old_time = new_time;
                 }
+
+ /* Drive the completion. */
+ if ( interrupted() )
+ rstat = EXEC_CMD_INTR;
+ else if ( status )
+ rstat = EXEC_CMD_FAIL;
+ else
+ rstat = EXEC_CMD_OK;
+
+ /* Call the callback, may call back to jam rule land. */
+ (*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat, &time_info,
+ cmdtab[ i ].buffer[ OUT ], cmdtab[ i ].buffer[ ERR ],
+ cmdtab[ i ].exit_reason );
+
+ /* Clean up the command's running commands table slot. */
+ BJAM_FREE( cmdtab[ i ].buffer[ OUT ] );
+ cmdtab[ i ].buffer[ OUT ] = 0;
+ cmdtab[ i ].buf_size[ OUT ] = 0;
+
+ BJAM_FREE( cmdtab[ i ].buffer[ ERR ] );
+ cmdtab[ i ].buffer[ ERR ] = 0;
+ cmdtab[ i ].buf_size[ ERR ] = 0;
+
+ cmdtab[ i ].pid = 0;
+ cmdtab[ i ].func = 0;
+ cmdtab[ i ].closure = 0;
+ cmdtab[ i ].start_time = 0;
             }
         }
     }
-
- return 1;
 }
 
-void exec_done( void )
+
+/*
+ * Find a free slot in the running commands table.
+ */
+
+static int get_free_cmdtab_slot()
 {
- int i;
- for( i = 0; i < MAXJOBS; ++i )
- {
- if( ! cmdtab[i].action ) break;
- BJAM_FREE( cmdtab[i].action );
- BJAM_FREE( cmdtab[i].target );
- }
+ int slot;
+ for ( slot = 0; slot < MAXJOBS; ++slot )
+ if ( !cmdtab[ slot ].pid )
+ return slot;
+ printf( "no slots for child!\n" );
+ exit( EXITBAD );
 }
 
 # endif /* USE_EXECUNIX */

Modified: branches/release/tools/build/v2/engine/filent.c
==============================================================================
--- branches/release/tools/build/v2/engine/filent.c (original)
+++ branches/release/tools/build/v2/engine/filent.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,286 +4,311 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Copyright 2005 Rene Rivera.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * Copyright 2005 Rene Rivera.
+ * 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)
  */
 
-# include "jam.h"
-
-# include "filesys.h"
-# include "pathsys.h"
-# include "strings.h"
-# include "object.h"
-
-# ifdef OS_NT
-
-# ifdef __BORLANDC__
-# if __BORLANDC__ < 0x550
-# include <dir.h>
-# include <dos.h>
-# endif
-# undef FILENAME /* cpp namespace collision */
-# define _finddata_t ffblk
-# endif
-
-# include <io.h>
-# include <sys/stat.h>
-# include <ctype.h>
-# include <direct.h>
-
 /*
  * filent.c - scan directories and archives on NT
  *
  * External routines:
+ * file_archscan() - scan an archive for files
+ * file_mkdir() - create a directory
+ * file_supported_fmt_resolution() - file modification timestamp resolution
  *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 07/10/95 (taylor) Findfirst() returns the first file on NT.
- * 05/03/96 (seiwald) split apart into pathnt.c
+ * External routines called only via routines in filesys.c:
+ * file_collect_dir_content_() - collects directory content information
+ * file_dirscan_() - OS specific file_dirscan() implementation
+ * file_query_() - query information about a path from the OS
  */
 
+#include "jam.h"
+#ifdef OS_NT
+#include "filesys.h"
+
+#include "object.h"
+#include "pathsys.h"
+#include "strings.h"
+
+#ifdef __BORLANDC__
+# undef FILENAME /* cpp namespace collision */
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <direct.h>
+#include <io.h>
+
+
 /*
- * file_dirscan() - scan a directory for files
+ * file_collect_dir_content_() - collects directory content information
  */
 
-void file_dirscan( OBJECT * dir, scanback func, void * closure )
+int file_collect_dir_content_( file_info_t * const d )
 {
- PROFILE_ENTER( FILE_DIRSCAN );
-
- file_info_t * d = 0;
-
- /* First enter directory itself */
-
- d = file_query( dir );
-
- if ( !d || !d->is_dir )
+ PATHNAME f;
+ string pathspec[ 1 ];
+ string pathname[ 1 ];
+ LIST * files = L0;
+ int d_length;
+
+ assert( d );
+ assert( d->is_dir );
+ assert( list_empty( d->files ) );
+
+ d_length = strlen( object_str( d->name ) );
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+ f.f_dir.ptr = object_str( d->name );
+ f.f_dir.len = d_length;
+
+ /* Prepare file search specification for the FindXXX() Windows API. */
+ if ( !d_length )
+ string_copy( pathspec, ".\\*" );
+ else
     {
- object_free( dir );
- PROFILE_EXIT( FILE_DIRSCAN );
- return;
+ /* We can not simply assume the given folder name will never include its
+ * trailing path separator or otherwise we would not support the Windows
+ * root folder specified without its drive letter, i.e. '\'.
+ */
+ char const trailingChar = object_str( d->name )[ d_length - 1 ] ;
+ string_copy( pathspec, object_str( d->name ) );
+ if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
+ string_append( pathspec, "\\" );
+ string_append( pathspec, "*" );
     }
 
- if ( !d->files )
+ /* The following code for collecting information about all files in a folder
+ * needs to be kept synchronized with how the file_query() operation is
+ * implemented (collects information about a single file).
+ */
     {
- PATHNAME f;
- string filespec[ 1 ];
- string filename[ 1 ];
- long handle;
- int ret;
- struct _finddata_t finfo[ 1 ];
- LIST * files = L0;
- int d_length;
-
- dir = short_path_to_long_path( dir );
-
- d_length = strlen( object_str( dir ) );
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = object_str( dir );
- f.f_dir.len = d_length;
-
- /* Now enter contents of directory */
-
- /* Prepare file search specification for the findfirst() API. */
- if ( d_length == 0 )
- string_copy( filespec, ".\\*" );
- else
- {
- /*
- * We can not simply assume the given folder name will never include
- * its trailing path separator or otherwise we would not support the
- * Windows root folder specified without its drive letter, i.e. '\'.
- */
- char trailingChar = object_str( dir )[ d_length - 1 ] ;
- string_copy( filespec, object_str( dir ) );
- if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
- string_append( filespec, "\\" );
- string_append( filespec, "*" );
+ /* FIXME: Avoid duplicate FindXXX Windows API calls here and in the code
+ * determining a normalized path.
+ */
+ WIN32_FIND_DATA finfo;
+ HANDLE const findHandle = FindFirstFileA( pathspec->value, &finfo );
+ if ( findHandle == INVALID_HANDLE_VALUE )
+ {
+ string_free( pathspec );
+ return -1;
+ }
+
+ string_new( pathname );
+ do
+ {
+ OBJECT * pathname_obj;
+
+ f.f_base.ptr = finfo.cFileName;
+ f.f_base.len = strlen( finfo.cFileName );
+
+ string_truncate( pathname, 0 );
+ path_build( &f, pathname );
+
+ pathname_obj = object_new( pathname->value );
+ path_register_key( pathname_obj );
+ files = list_push_back( files, pathname_obj );
+ {
+ int found;
+ file_info_t * const ff = file_info( pathname_obj, &found );
+ ff->is_dir = finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ ff->is_file = !ff->is_dir;
+ ff->exists = 1;
+ timestamp_from_filetime( &ff->time, &finfo.ftLastWriteTime );
+ }
         }
+ while ( FindNextFile( findHandle, &finfo ) );
 
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- #if defined(__BORLANDC__) && __BORLANDC__ < 0x550
- if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
- {
- string_free( filespec );
- object_free( dir );
- PROFILE_EXIT( FILE_DIRSCAN );
- return;
- }
+ FindClose( findHandle );
+ }
 
- string_new ( filename );
- while ( !ret )
- {
- file_info_t * ff = 0;
+ string_free( pathname );
+ string_free( pathspec );
 
- f.f_base.ptr = finfo->ff_name;
- f.f_base.len = strlen( finfo->ff_name );
+ d->files = files;
+ return 0;
+}
 
- string_truncate( filename, 0 );
- path_build( &f, filename );
 
- files = list_push_back( files, object_new(filename->value) );
- ff = file_info( filename->value );
- ff->is_file = finfo->ff_attrib & FA_DIREC ? 0 : 1;
- ff->is_dir = finfo->ff_attrib & FA_DIREC ? 1 : 0;
- ff->size = finfo->ff_fsize;
- ff->time = (finfo->ff_ftime << 16) | finfo->ff_ftime;
+/*
+ * file_dirscan_() - OS specific file_dirscan() implementation
+ */
 
- ret = findnext( finfo );
- }
- # else
- handle = _findfirst( filespec->value, finfo );
+void file_dirscan_( file_info_t * const d, scanback func, void * closure )
+{
+ assert( d );
+ assert( d->is_dir );
 
- if ( ret = ( handle < 0L ) )
+ /* Special case \ or d:\ : enter it */
+ {
+ char const * const name = object_str( d->name );
+ if ( name[ 0 ] == '\\' && !name[ 1 ] )
         {
- string_free( filespec );
- object_free( dir );
- PROFILE_EXIT( FILE_DIRSCAN );
- return;
+ (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
         }
-
- string_new( filename );
- while ( !ret )
+ else if ( name[ 0 ] && name[ 1 ] == ':' && name[ 2 ] && !name[ 3 ] )
         {
- OBJECT * filename_obj;
- file_info_t * ff = 0;
+ /* We have just entered a 3-letter drive name spelling (with a
+ * trailing slash), into the hash table. Now enter its two-letter
+ * variant, without the trailing slash, so that if we try to check
+ * whether "c:" exists, we hit it.
+ *
+ * Jam core has workarounds for that. Given:
+ * x = c:\whatever\foo ;
+ * p = $(x:D) ;
+ * p2 = $(p:D) ;
+ * There will be no trailing slash in $(p), but there will be one in
+ * $(p2). But, that seems rather fragile.
+ */
+ OBJECT * const dir_no_slash = object_new_range( name, 2 );
+ (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
+ (*func)( closure, dir_no_slash, 1 /* stat()'ed */, &d->time );
+ object_free( dir_no_slash );
+ }
+ }
+}
 
- f.f_base.ptr = finfo->name;
- f.f_base.len = strlen( finfo->name );
 
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
+/*
+ * file_mkdir() - create a directory
+ */
 
- filename_obj = object_new( filename->value );
- path_add_key( filename_obj );
- files = list_push_back( files, filename_obj );
- ff = file_info( filename_obj );
- ff->is_file = finfo->attrib & _A_SUBDIR ? 0 : 1;
- ff->is_dir = finfo->attrib & _A_SUBDIR ? 1 : 0;
- ff->size = finfo->size;
- ff->time = finfo->time_write;
+int file_mkdir( char const * const path )
+{
+ return _mkdir( path );
+}
 
- ret = _findnext( handle, finfo );
- }
 
- _findclose( handle );
- # endif
- string_free( filename );
- string_free( filespec );
- object_free( dir );
+/*
+ * file_query_() - query information about a path from the OS
+ *
+ * The following code for collecting information about a single file needs to be
+ * kept synchronized with how the file_collect_dir_content_() operation is
+ * implemented (collects information about all files in a folder).
+ */
 
- d->files = files;
+int try_file_query_root( file_info_t * const info )
+{
+ WIN32_FILE_ATTRIBUTE_DATA fileData;
+ char buf[ 4 ];
+ char const * const pathstr = object_str( info->name );
+ if ( !pathstr[ 0 ] )
+ {
+ buf[ 0 ] = '.';
+ buf[ 1 ] = 0;
     }
-
- /* Special case \ or d:\ : enter it */
+ else if ( pathstr[ 0 ] == '\\' && ! pathstr[ 1 ] )
+ {
+ buf[ 0 ] = '\\';
+ buf[ 1 ] = '\0';
+ }
+ else if ( pathstr[ 1 ] == ':' )
     {
- unsigned long len = strlen( object_str( d->name ) );
- if ( len == 1 && object_str( d->name )[0] == '\\' )
+ if ( !pathstr[ 2 ] )
         {
- OBJECT * dir = short_path_to_long_path( d->name );
- (*func)( closure, dir, 1 /* stat()'ed */, d->time );
- object_free( dir );
         }
- else if ( len == 3 && object_str( d->name )[1] == ':' )
+ else if ( !pathstr[ 2 ] || ( pathstr[ 2 ] == '\\' && !pathstr[ 3 ] ) )
         {
- char buf[4];
- OBJECT * dir1 = short_path_to_long_path( d->name );
- OBJECT * dir2;
- (*func)( closure, dir1, 1 /* stat()'ed */, d->time );
- /* We've just entered 3-letter drive name spelling (with trailing
- slash), into the hash table. Now enter two-letter variant,
- without trailing slash, so that if we try to check whether
- "c:" exists, we hit it.
-
- Jam core has workarounds for that. Given:
- x = c:\whatever\foo ;
- p = $(x:D) ;
- p2 = $(p:D) ;
- There will be no trailing slash in $(p), but there will be one
- in $(p2). But, that seems rather fragile.
- */
- strcpy( buf, object_str( dir1 ) );
- buf[2] = 0;
- dir2 = object_new( buf );
- (*func)( closure, dir2, 1 /* stat()'ed */, d->time );
- object_free( dir2 );
- object_free( dir1 );
+ buf[ 0 ] = pathstr[ 0 ];
+ buf[ 1 ] = ':';
+ buf[ 2 ] = '\\';
+ buf[ 3 ] = '\0';
         }
- }
-
- /* Now enter contents of directory */
- if ( !list_empty( d->files ) )
- {
- LIST * files = d->files;
- LISTITER iter = list_begin( files ), end = list_end( files );
- for ( ; iter != end; iter = list_next( iter ) )
+ else
         {
- file_info_t * ff = file_info( list_item( iter ) );
- (*func)( closure, list_item( iter ), 1 /* stat()'ed */, ff->time );
+ return 0;
         }
     }
-
- PROFILE_EXIT( FILE_DIRSCAN );
+ else
+ {
+ return 0;
+ }
+
+ /* We have a root path */
+ if ( !GetFileAttributesExA( buf, GetFileExInfoStandard, &fileData ) )
+ {
+ info->is_dir = 0;
+ info->is_file = 0;
+ info->exists = 0;
+ timestamp_clear( &info->time );
+ }
+ else
+ {
+ info->is_dir = fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ info->is_file = !info->is_dir;
+ info->exists = 1;
+ timestamp_from_filetime( &info->time, &fileData.ftLastWriteTime );
+ }
+ return 1;
 }
 
-file_info_t * file_query( OBJECT * filename )
+void file_query_( file_info_t * const info )
 {
- file_info_t * ff = file_info( filename );
- if ( ! ff->time )
- {
- struct stat statbuf;
+ char const * const pathstr = object_str( info->name );
+ const char * dir;
+ OBJECT * parent;
+ file_info_t * parent_info;
 
- if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
- return 0;
+ if ( try_file_query_root( info ) )
+ return;
 
- ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
- ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
- ff->size = statbuf.st_size;
- ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
+ if ( ( dir = strrchr( pathstr, '\\' ) ) )
+ {
+ parent = object_new_range( pathstr, dir - pathstr );
+ }
+ else
+ {
+ parent = object_copy( constant_empty );
+ }
+ parent_info = file_query( parent );
+ object_free( parent );
+ if ( !parent_info || !parent_info->is_dir )
+ {
+ info->is_dir = 0;
+ info->is_file = 0;
+ info->exists = 0;
+ timestamp_clear( &info->time );
+ }
+ else
+ {
+ info->is_dir = 0;
+ info->is_file = 0;
+ info->exists = 0;
+ timestamp_clear( &info->time );
+ if ( list_empty( parent_info->files ) )
+ file_collect_dir_content_( parent_info );
     }
- return ff;
 }
 
+
 /*
- * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_supported_fmt_resolution() - file modification timestamp resolution
+ *
+ * Returns the minimum file modification timestamp resolution supported by this
+ * Boost Jam implementation. File modification timestamp changes of less than
+ * the returned value might not be recognized.
+ *
+ * Does not take into consideration any OS or file system related restrictions.
+ *
+ * Return value 0 indicates that any value supported by the OS is also supported
+ * here.
  */
 
-int
-file_time(
- OBJECT * filename,
- time_t * time )
+void file_supported_fmt_resolution( timestamp * const t )
 {
- file_info_t * ff = file_query( filename );
- if ( !ff ) return -1;
- *time = ff->time;
- return 0;
-}
-
-int file_is_file( OBJECT * filename )
-{
- file_info_t * ff = file_query( filename );
- if ( !ff ) return -1;
- return ff->is_file;
+ /* On Windows we support nano-second file modification timestamp resolution,
+ * just the same as the Windows OS itself.
+ */
+ timestamp_init( t, 0, 0 );
 }
 
-int file_mkdir( const char * pathname )
-{
- return _mkdir(pathname);
-}
 
 /*
  * file_archscan() - scan an archive for files
@@ -291,41 +316,37 @@
 
 /* Straight from SunOS */
 
-#define ARMAG "!<arch>\n"
+#define ARMAG "!<arch>\n"
 #define SARMAG 8
 
 #define ARFMAG "`\n"
 
-struct ar_hdr {
- char ar_name[16];
- char ar_date[12];
- char ar_uid[6];
- char ar_gid[6];
- char ar_mode[8];
- char ar_size[10];
- char ar_fmag[2];
+struct ar_hdr
+{
+ char ar_name[ 16 ];
+ char ar_date[ 12 ];
+ char ar_uid[ 6 ];
+ char ar_gid[ 6 ];
+ char ar_mode[ 8 ];
+ char ar_size[ 10 ];
+ char ar_fmag[ 2 ];
 };
 
-# define SARFMAG 2
-# define SARHDR sizeof( struct ar_hdr )
+#define SARFMAG 2
+#define SARHDR sizeof( struct ar_hdr )
 
-void
-file_archscan(
- const char * archive,
- scanback func,
- void * closure )
+void file_archscan( char const * archive, scanback func, void * closure )
 {
     struct ar_hdr ar_hdr;
- char *string_table = 0;
+ char * string_table = 0;
     char buf[ MAXJPATH ];
     long offset;
- int fd;
+ int const fd = open( archive, O_RDONLY | O_BINARY, 0 );
 
- if ( ( fd = open( archive, O_RDONLY | O_BINARY, 0 ) ) < 0 )
+ if ( fd < 0 )
         return;
 
- if ( read( fd, buf, SARMAG ) != SARMAG ||
- strncmp( ARMAG, buf, SARMAG ) )
+ if ( read( fd, buf, SARMAG ) != SARMAG || strncmp( ARMAG, buf, SARMAG ) )
     {
         close( fd );
         return;
@@ -337,43 +358,39 @@
         printf( "scan archive %s\n", archive );
 
     while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
- !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
+ !memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG ) )
     {
- long lar_date;
- long lar_size;
- char * name = 0;
- char * endname;
- char * c;
- OBJECT * member;
+ long lar_date;
+ long lar_size;
+ char * name = 0;
+ char * endname;
 
         sscanf( ar_hdr.ar_date, "%ld", &lar_date );
         sscanf( ar_hdr.ar_size, "%ld", &lar_size );
 
         lar_size = ( lar_size + 1 ) & ~1;
 
- if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] == '/' )
- {
- /* this is the "string table" entry of the symbol table,
- ** which holds strings of filenames that are longer than
- ** 15 characters (ie. don't fit into a ar_name
- */
-
- string_table = BJAM_MALLOC_ATOMIC(lar_size+1);
- if (read(fd, string_table, lar_size) != lar_size)
- printf("error reading string table\n");
- string_table[lar_size] = '\0';
- offset += SARHDR + lar_size;
- continue;
- }
- else if (ar_hdr.ar_name[0] == '/' && ar_hdr.ar_name[1] != ' ')
+ if ( ar_hdr.ar_name[ 0 ] == '/' && ar_hdr.ar_name[ 1 ] == '/' )
         {
- /* Long filenames are recognized by "/nnnn" where nnnn is
- ** the offset of the string in the string table represented
- ** in ASCII decimals.
- */
-
+ /* This is the "string table" entry of the symbol table, holding
+ * filename strings longer than 15 characters, i.e. those that do
+ * not fit into ar_name.
+ */
+ string_table = BJAM_MALLOC_ATOMIC( lar_size + 1 );
+ if ( read( fd, string_table, lar_size ) != lar_size )
+ printf( "error reading string table\n" );
+ string_table[ lar_size ] = '\0';
+ offset += SARHDR + lar_size;
+ continue;
+ }
+ else if ( ar_hdr.ar_name[ 0 ] == '/' && ar_hdr.ar_name[ 1 ] != ' ' )
+ {
+ /* Long filenames are recognized by "/nnnn" where nnnn is the
+ * string's offset in the string table represented in ASCII
+ * decimals.
+ */
             name = string_table + atoi( ar_hdr.ar_name + 1 );
- for ( endname = name; *endname && *endname != '\n'; ++endname) {}
+ for ( endname = name; *endname && *endname != '\n'; ++endname );
         }
         else
         {
@@ -385,21 +402,28 @@
         /* strip trailing white-space, slashes, and backslashes */
 
         while ( endname-- > name )
- if ( !isspace(*endname) && ( *endname != '\\' ) && ( *endname != '/' ) )
+ if ( !isspace( *endname ) && ( *endname != '\\' ) && ( *endname !=
+ '/' ) )
                 break;
         *++endname = 0;
 
         /* strip leading directory names, an NT specialty */
-
- if ( c = strrchr( name, '/' ) )
- name = c + 1;
- if ( c = strrchr( name, '\\' ) )
- name = c + 1;
+ {
+ char * c;
+ if ( c = strrchr( name, '/' ) )
+ name = c + 1;
+ if ( c = strrchr( name, '\\' ) )
+ name = c + 1;
+ }
 
         sprintf( buf, "%s(%.*s)", archive, endname - name, name );
- member = object_new( buf );
- (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
- object_free( member );
+ {
+ OBJECT * const member = object_new( buf );
+ timestamp time;
+ timestamp_init( &time, (time_t)lar_date, 0 );
+ (*func)( closure, member, 1 /* time valid */, &time );
+ object_free( member );
+ }
 
         offset += SARHDR + lar_size;
         lseek( fd, offset, 0 );
@@ -408,4 +432,4 @@
     close( fd );
 }
 
-# endif /* NT */
+#endif /* OS_NT */

Modified: branches/release/tools/build/v2/engine/filesys.c
==============================================================================
--- branches/release/tools/build/v2/engine/filesys.c (original)
+++ branches/release/tools/build/v2/engine/filesys.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,15 +1,69 @@
-# include "jam.h"
-# include "pathsys.h"
-# include "strings.h"
-# include "object.h"
-# include "filesys.h"
-# include "lists.h"
+/*
+ * Copyright 2001-2004 David Abrahams.
+ * Copyright 2005 Rene Rivera.
+ * 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)
+ */
+
+/*
+ * filesys.c - OS independant file system manipulation support
+ *
+ * External routines:
+ * file_build1() - construct a path string based on PATHNAME information
+ * file_dirscan() - scan a directory for files
+ * file_done() - module cleanup called on shutdown
+ * file_info() - return cached information about a path
+ * file_is_file() - return whether a path identifies an existing file
+ * file_query() - get cached information about a path, query the OS if
+ * needed
+ * file_remove_atexit() - schedule a path to be removed on program exit
+ * file_time() - get a file timestamp
+ *
+ * External routines - utilites for OS specific module implementations:
+ * file_query_posix_() - query information about a path using POSIX stat()
+ *
+ * Internal routines:
+ * file_dirscan_impl() - no-profiling worker for file_dirscan()
+ */
+
+
+#include "jam.h"
+#include "filesys.h"
+
+#include "lists.h"
+#include "object.h"
+#include "pathsys.h"
+#include "strings.h"
+
+#include <assert.h>
+#include <sys/stat.h>
+
+
+/* Internal OS specific implementation details - have names ending with an
+ * underscore and are expected to be implemented in an OS specific fileXXX.c
+ * module.
+ */
+void file_dirscan_( file_info_t * const dir, scanback func, void * closure );
+int file_collect_dir_content_( file_info_t * const dir );
+void file_query_( file_info_t * const );
+
+static void file_dirscan_impl( OBJECT * dir, scanback func, void * closure );
+static void free_file_info( void * xfile, void * data );
+static void remove_files_atexit( void );
+
+
+static struct hash * filecache_hash;
+
+
+/*
+ * file_build1() - construct a path string based on PATHNAME information
+ */
 
-void file_build1( PATHNAME * f, string * file )
+void file_build1( PATHNAME * const f, string * file )
 {
     if ( DEBUG_SEARCH )
     {
- printf("build file: ");
+ printf( "build file: " );
         if ( f->f_root.len )
             printf( "root = '%.*s' ", f->f_root.len, f->f_root.ptr );
         if ( f->f_dir.len )
@@ -19,81 +73,254 @@
         printf( "\n" );
     }
 
- /* Start with the grist. If the current grist isn't */
- /* surrounded by <>'s, add them. */
-
+ /* Start with the grist. If the current grist is not surrounded by <>'s, add
+ * them.
+ */
     if ( f->f_grist.len )
     {
- if ( f->f_grist.ptr[0] != '<' )
+ if ( f->f_grist.ptr[ 0 ] != '<' )
             string_push_back( file, '<' );
         string_append_range(
             file, f->f_grist.ptr, f->f_grist.ptr + f->f_grist.len );
- if ( file->value[file->size - 1] != '>' )
+ if ( file->value[ file->size - 1 ] != '>' )
             string_push_back( file, '>' );
     }
 }
 
-static struct hash * filecache_hash = 0;
-static file_info_t filecache_finfo;
 
-file_info_t * file_info( OBJECT * filename )
+/*
+ * file_dirscan() - scan a directory for files
+ */
+
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
 {
- file_info_t *finfo = &filecache_finfo;
- int found;
+ PROFILE_ENTER( FILE_DIRSCAN );
+ file_dirscan_impl( dir, func, closure );
+ PROFILE_EXIT( FILE_DIRSCAN );
+}
+
+
+/*
+ * file_done() - module cleanup called on shutdown
+ */
+
+void file_done()
+{
+ remove_files_atexit();
+ if ( filecache_hash )
+ {
+ hashenumerate( filecache_hash, free_file_info, (void *)0 );
+ hashdone( filecache_hash );
+ }
+}
+
+
+/*
+ * file_info() - return cached information about a path
+ *
+ * Returns a default initialized structure containing only the path's normalized
+ * name in case this is the first time this file system entity has been
+ * referenced.
+ */
+
+file_info_t * file_info( OBJECT * const path, int * found )
+{
+ OBJECT * const path_key = path_as_key( path );
+ file_info_t * finfo;
 
     if ( !filecache_hash )
         filecache_hash = hashinit( sizeof( file_info_t ), "file_info" );
 
- filename = path_as_key( filename );
-
- finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found );
- if ( !found )
+ finfo = (file_info_t *)hash_insert( filecache_hash, path_key, found );
+ if ( !*found )
     {
- /* printf( "file_info: %s\n", filename ); */
- finfo->name = object_copy( filename );
- finfo->is_file = 0;
- finfo->is_dir = 0;
- finfo->size = 0;
- finfo->time = 0;
+ finfo->name = path_key;
         finfo->files = L0;
     }
-
- object_free( filename );
+ else
+ object_free( path_key );
 
     return finfo;
 }
 
-static LIST * files_to_remove = L0;
 
-static void remove_files_atexit(void)
+/*
+ * file_is_file() - return whether a path identifies an existing file
+ */
+
+int file_is_file( OBJECT * const path )
 {
- LISTITER iter = list_begin( files_to_remove ), end = list_end( files_to_remove );
- for ( ; iter != end; iter = list_next( iter ) )
+ file_info_t const * const ff = file_query( path );
+ return ff ? ff->is_file : -1;
+}
+
+
+/*
+ * file_time() - get a file timestamp
+ */
+
+int file_time( OBJECT * const path, timestamp * const time )
+{
+ file_info_t const * const ff = file_query( path );
+ if ( !ff ) return -1;
+ timestamp_copy( time, &ff->time );
+ return 0;
+}
+
+
+/*
+ * file_query() - get cached information about a path, query the OS if needed
+ *
+ * Returns 0 in case querying the OS about the given path fails, e.g. because
+ * the path does not reference an existing file system object.
+ */
+
+file_info_t * file_query( OBJECT * const path )
+{
+ /* FIXME: Add tracking for disappearing files (i.e. those that can not be
+ * detected by stat() even though they had been detected successfully
+ * before) and see how they should be handled in the rest of Boost Jam code.
+ * Possibly allow Jamfiles to specify some files as 'volatile' which would
+ * make Boost Jam avoid caching information about those files and instead
+ * ask the OS about them every time.
+ */
+ int found;
+ file_info_t * const ff = file_info( path, &found );
+ if ( !found )
     {
- remove( object_str( list_item( iter ) ) );
+ file_query_( ff );
+ if ( ff->exists )
+ {
+ /* Set the path's timestamp to 1 in case it is 0 or undetected to avoid
+ * confusion with non-existing paths.
+ */
+ if ( timestamp_empty( &ff->time ) )
+ timestamp_init( &ff->time, 1, 0 );
+ }
     }
- list_free( files_to_remove );
- files_to_remove = L0;
+ if ( !ff->exists )
+ {
+ return 0;
+ }
+ return ff;
 }
 
-static void free_file_info ( void * xfile, void * data )
+
+/*
+ * file_query_posix_() - query information about a path using POSIX stat()
+ *
+ * Fallback file_query_() implementation for OS specific modules.
+ *
+ * Note that the Windows POSIX stat() function implementation suffers from
+ * several issues:
+ * * Does not support file timestamps with resolution finer than 1 second,
+ * meaning it can not be used to detect file timestamp changes of less than
+ * 1 second. One possible consequence is that some fast-paced touch commands
+ * (such as those done by Boost Build's internal testing system if it does
+ * not do some extra waiting) will not be detected correctly by the build
+ * system.
+ * * Returns file modification times automatically adjusted for daylight
+ * savings time even though daylight savings time should have nothing to do
+ * with internal time representation.
+ */
+
+void file_query_posix_( file_info_t * const info )
 {
- file_info_t * file = (file_info_t *)xfile;
- object_free( file->name );
- list_free( file->files );
+ struct stat statbuf;
+ char const * const pathstr = object_str( info->name );
+ char const * const pathspec = *pathstr ? pathstr : ".";
+
+ if ( stat( pathspec, &statbuf ) < 0 )
+ {
+ info->is_file = 0;
+ info->is_dir = 0;
+ info->exists = 0;
+ timestamp_clear( &info->time );
+ }
+ else
+ {
+ info->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
+ info->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
+ info->exists = 1;
+ timestamp_init( &info->time, statbuf.st_mtime, 0 );
+ }
 }
 
-void file_done()
+
+/*
+ * file_remove_atexit() - schedule a path to be removed on program exit
+ */
+
+static LIST * files_to_remove = L0;
+
+void file_remove_atexit( OBJECT * const path )
 {
- remove_files_atexit();
- if ( filecache_hash )
+ files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
+}
+
+
+/*
+ * file_dirscan_impl() - no-profiling worker for file_dirscan()
+ */
+
+static void file_dirscan_impl( OBJECT * dir, scanback func, void * closure )
+{
+ file_info_t * const d = file_query( dir );
+ if ( !d || !d->is_dir )
+ return;
+
+ /* Lazy collect the directory content information. */
+ if ( list_empty( d->files ) )
     {
- hashenumerate( filecache_hash, free_file_info, (void *)0 );
- hashdone( filecache_hash );
+ if ( DEBUG_BINDSCAN )
+ printf( "scan directory %s\n", object_str( d->name ) );
+ if ( file_collect_dir_content_( d ) < 0 )
+ return;
+ }
+
+ /* OS specific part of the file_dirscan operation. */
+ file_dirscan_( d, func, closure );
+
+ /* Report the collected directory content. */
+ {
+ LISTITER iter = list_begin( d->files );
+ LISTITER const end = list_end( d->files );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ OBJECT * const path = list_item( iter );
+ file_info_t const * const ffq = file_query( path );
+ /* Using a file name read from a file_info_t structure allows OS
+ * specific implementations to store some kind of a normalized file
+ * name there. Using such a normalized file name then allows us to
+ * correctly recognize different file paths actually identifying the
+ * same file. For instance, an implementation may:
+ * - convert all file names internally to lower case on a case
+ * insensitive file system
+ * - convert the NTFS paths to their long path variants as that
+ * file system each file system entity may have a long and a
+ * short path variant thus allowing for many different path
+ * strings identifying the same file.
+ */
+ (*func)( closure, ffq->name, 1 /* stat()'ed */, &ffq->time );
+ }
     }
 }
 
-void file_remove_atexit( OBJECT * path )
+
+static void free_file_info( void * xfile, void * data )
 {
- files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
+ file_info_t * const file = (file_info_t *)xfile;
+ object_free( file->name );
+ list_free( file->files );
+}
+
+
+static void remove_files_atexit( void )
+{
+ LISTITER iter = list_begin( files_to_remove );
+ LISTITER const end = list_end( files_to_remove );
+ for ( ; iter != end; iter = list_next( iter ) )
+ remove( object_str( list_item( iter ) ) );
+ list_free( files_to_remove );
+ files_to_remove = L0;
 }

Modified: branches/release/tools/build/v2/engine/filesys.h
==============================================================================
--- branches/release/tools/build/v2/engine/filesys.h (original)
+++ branches/release/tools/build/v2/engine/filesys.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -15,47 +15,43 @@
  */
 
 #ifndef FILESYS_DWA20011025_H
-# define FILESYS_DWA20011025_H
+#define FILESYS_DWA20011025_H
 
-# include "pathsys.h"
 #include "hash.h"
 #include "lists.h"
 #include "object.h"
+#include "pathsys.h"
+#include "timestamp.h"
 
-typedef void (*scanback)( void *closure, OBJECT * file, int found, time_t t );
 
-void file_dirscan( OBJECT * dir, scanback func, void * closure );
-void file_archscan( const char * arch, scanback func, void * closure );
-
-int file_time( OBJECT * filename, time_t * time );
-
-void file_build1(PATHNAME *f, string* file) ;
-int file_is_file( OBJECT * filename );
-int file_mkdir( const char * pathname );
-
-typedef struct file_info_t file_info_t ;
-struct file_info_t
+typedef struct file_info_t
 {
- OBJECT * name;
- short is_file;
- short is_dir;
- unsigned long size;
- time_t time;
- LIST * files;
-};
+ OBJECT * name;
+ char is_file;
+ char is_dir;
+ char exists;
+ timestamp time;
+ LIST * files;
+} file_info_t;
 
+typedef void (*scanback)( void * closure, OBJECT * path, int found,
+ timestamp const * const );
 
-/* Creates a pointer to information about file 'filename', creating it as
- * necessary. If created, the structure will be default initialized.
- */
-file_info_t * file_info( OBJECT * filename );
 
-/* Returns information about a file, queries the OS if needed. */
-file_info_t * file_query( OBJECT * filename );
+void file_archscan( char const * arch, scanback func, void * closure );
+void file_build1( PATHNAME * const f, string * file ) ;
+void file_dirscan( OBJECT * dir, scanback func, void * closure );
+file_info_t * file_info( OBJECT * const path, int * found );
+int file_is_file( OBJECT * const path );
+int file_mkdir( char const * const path );
+file_info_t * file_query( OBJECT * const path );
+void file_remove_atexit( OBJECT * const path );
+void file_supported_fmt_resolution( timestamp * const );
+int file_time( OBJECT * const path, timestamp * const );
+
+/* Internal utility worker functions. */
+void file_query_posix_( file_info_t * const );
 
 void file_done();
 
-/* Marks a path/file to be removed when jam exits. */
-void file_remove_atexit( OBJECT * path );
-
 #endif

Modified: branches/release/tools/build/v2/engine/fileunix.c
==============================================================================
--- branches/release/tools/build/v2/engine/fileunix.c (original)
+++ branches/release/tools/build/v2/engine/fileunix.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,277 +11,225 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-# include "jam.h"
-# include "filesys.h"
-# include "strings.h"
-# include "pathsys.h"
-# include "object.h"
-# include <stdio.h>
-# include <sys/stat.h>
-
-#if defined(sun) || defined(__sun) || defined(linux)
-# include <unistd.h> /* needed for read and close prototype */
-#endif
+/*
+ * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
+ *
+ * External routines:
+ * file_archscan() - scan an archive for files
+ * file_mkdir() - create a directory
+ * file_supported_fmt_resolution() - file modification timestamp resolution
+ *
+ * External routines called only via routines in filesys.c:
+ * file_collect_dir_content_() - collects directory content information
+ * file_dirscan_() - OS specific file_dirscan() implementation
+ * file_query_() - query information about a path from the OS
+ */
 
-# ifdef USE_FILEUNIX
+#include "jam.h"
+#ifdef USE_FILEUNIX
+#include "filesys.h"
+
+#include "object.h"
+#include "pathsys.h"
+#include "strings.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/stat.h> /* needed for mkdir() */
 
-#if defined(sun) || defined(__sun)
-# include <unistd.h> /* needed for read and close prototype */
+#if defined( sun ) || defined( __sun ) || defined( linux )
+# include <unistd.h> /* needed for read and close prototype */
 #endif
 
-# if defined( OS_SEQUENT ) || \
- defined( OS_DGUX ) || \
- defined( OS_SCO ) || \
- defined( OS_ISC )
+#if defined( OS_SEQUENT ) || \
+ defined( OS_DGUX ) || \
+ defined( OS_SCO ) || \
+ defined( OS_ISC )
 # define PORTAR 1
-# endif
-
-# ifdef __EMX__
-# include <sys/types.h>
-# include <sys/stat.h>
-# endif
+#endif
 
-# if defined( OS_RHAPSODY ) || \
- defined( OS_MACOSX ) || \
- defined( OS_NEXT )
-/* need unistd for rhapsody's proper lseek */
+#if defined( OS_RHAPSODY ) || defined( OS_MACOSX ) || defined( OS_NEXT )
 # include <sys/dir.h>
-# include <unistd.h>
+# include <unistd.h> /* need unistd for rhapsody's proper lseek */
 # define STRUCT_DIRENT struct direct
-# else
+#else
 # include <dirent.h>
 # define STRUCT_DIRENT struct dirent
-# endif
+#endif
 
-# ifdef OS_COHERENT
+#ifdef OS_COHERENT
 # include <arcoff.h>
 # define HAVE_AR
-# endif
-
-# if defined( OS_MVS ) || \
- defined( OS_INTERIX )
+#endif
 
-#define ARMAG "!<arch>\n"
+#if defined( OS_MVS ) || defined( OS_INTERIX )
+#define ARMAG "!<arch>\n"
 #define SARMAG 8
 #define ARFMAG "`\n"
+#define HAVE_AR
 
-struct ar_hdr /* archive file member header - printable ascii */
+struct ar_hdr /* archive file member header - printable ascii */
 {
- char ar_name[16]; /* file member name - `/' terminated */
- char ar_date[12]; /* file member date - decimal */
- char ar_uid[6]; /* file member user id - decimal */
- char ar_gid[6]; /* file member group id - decimal */
- char ar_mode[8]; /* file member mode - octal */
- char ar_size[10]; /* file member size - decimal */
- char ar_fmag[2]; /* ARFMAG - string to end header */
+ char ar_name[ 16 ]; /* file member name - `/' terminated */
+ char ar_date[ 12 ]; /* file member date - decimal */
+ char ar_uid[ 6 ]; /* file member user id - decimal */
+ char ar_gid[ 6 ]; /* file member group id - decimal */
+ char ar_mode[ 8 ]; /* file member mode - octal */
+ char ar_size[ 10 ]; /* file member size - decimal */
+ char ar_fmag[ 2 ]; /* ARFMAG - string to end header */
 };
+#endif
 
-# define HAVE_AR
-# endif
-
-# if defined( OS_QNX ) || \
- defined( OS_BEOS ) || \
- defined( OS_MPEIX )
+#if defined( OS_QNX ) || defined( OS_BEOS ) || defined( OS_MPEIX )
 # define NO_AR
 # define HAVE_AR
-# endif
-
-# ifndef HAVE_AR
+#endif
 
+#ifndef HAVE_AR
 # ifdef OS_AIX
-/* Define those for AIX to get the definitions for both the small and the
- * big variant of the archive file format. */
-# define __AR_SMALL__
-# define __AR_BIG__
+/* Define these for AIX to get the definitions for both small and big archive
+ * file format variants.
+ */
+# define __AR_SMALL__
+# define __AR_BIG__
 # endif
-
 # include <ar.h>
-# endif
-
-/*
- * fileunix.c - manipulate file names and scan directories on UNIX/AmigaOS
- *
- * External routines:
- *
- * file_dirscan() - scan a directory for files
- * file_time() - get timestamp of file, if not done by file_dirscan()
- * file_archscan() - scan an archive for files
- *
- * File_dirscan() and file_archscan() call back a caller provided function
- * for each file found. A flag to this callback function lets file_dirscan()
- * and file_archscan() indicate that a timestamp is being provided with the
- * file. If file_dirscan() or file_archscan() do not provide the file's
- * timestamp, interested parties may later call file_time().
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 12/19/94 (mikem) - solaris string table insanity support
- * 02/14/95 (seiwald) - parse and build /xxx properly
- * 05/03/96 (seiwald) - split into pathunix.c
- * 11/21/96 (peterk) - BEOS does not have Unix-style archives
- */
+#endif
 
 
 /*
- * file_dirscan() - scan a directory for files.
+ * file_collect_dir_content_() - collects directory content information
  */
 
-void file_dirscan( OBJECT * dir, scanback func, void * closure )
+int file_collect_dir_content_( file_info_t * const d )
 {
- PROFILE_ENTER( FILE_DIRSCAN );
-
- file_info_t * d = 0;
-
- d = file_query( dir );
-
- if ( !d || !d->is_dir )
- {
- PROFILE_EXIT( FILE_DIRSCAN );
- return;
+ LIST * files = L0;
+ PATHNAME f;
+ DIR * dd;
+ STRUCT_DIRENT * dirent;
+ string path[ 1 ];
+ char const * dirstr;
+
+ assert( d );
+ assert( d->is_dir );
+ assert( list_empty( d->files ) );
+
+ dirstr = object_str( d->name );
+
+ memset( (char *)&f, '\0', sizeof( f ) );
+ f.f_dir.ptr = dirstr;
+ f.f_dir.len = strlen( dirstr );
+
+ if ( !*dirstr ) dirstr = ".";
+
+ if ( !( dd = opendir( dirstr ) ) )
+ return -1;
+
+ string_new( path );
+ while ( ( dirent = readdir( dd ) ) )
+ {
+ OBJECT * name;
+ f.f_base.ptr = dirent->d_name
+ #ifdef old_sinix
+ - 2 /* Broken structure definition on sinix. */
+ #endif
+ ;
+ f.f_base.len = strlen( f.f_base.ptr );
+
+ string_truncate( path, 0 );
+ path_build( &f, path );
+ name = object_new( path->value );
+ /* Immediately stat the file to preserve invariants. */
+ if ( file_query( name ) )
+ files = list_push_back( files, name );
+ else
+ object_free( name );
     }
+ string_free( path );
 
- if ( list_empty( d->files ) )
- {
- LIST* files = L0;
- PATHNAME f;
- DIR *dd;
- STRUCT_DIRENT *dirent;
- string filename[1];
- const char * dirstr = object_str( dir );
-
- /* First enter directory itself */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dirstr;
- f.f_dir.len = strlen( dirstr );
+ closedir( dd );
 
- dirstr = *dirstr ? dirstr : ".";
-
- /* Now enter contents of directory. */
-
- if ( !( dd = opendir( dirstr ) ) )
- {
- PROFILE_EXIT( FILE_DIRSCAN );
- return;
- }
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dirstr );
+ d->files = files;
+ return 0;
+}
 
- string_new( filename );
- while ( ( dirent = readdir( dd ) ) )
- {
- OBJECT * filename_obj;
- # ifdef old_sinix
- /* Broken structure definition on sinix. */
- f.f_base.ptr = dirent->d_name - 2;
- # else
- f.f_base.ptr = dirent->d_name;
- # endif
- f.f_base.len = strlen( f.f_base.ptr );
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
-
- filename_obj = object_new( filename->value );
- files = list_push_back( files, filename_obj );
- file_query( filename_obj );
- }
- string_free( filename );
 
- closedir( dd );
+/*
+ * file_dirscan_() - OS specific file_dirscan() implementation
+ */
 
- d->files = files;
- }
+void file_dirscan_( file_info_t * const d, scanback func, void * closure )
+{
+ assert( d );
+ assert( d->is_dir );
 
     /* Special case / : enter it */
- {
- if ( strcmp( object_str( d->name ), "/" ) == 0 )
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
- }
-
- /* Now enter contents of directory */
- if ( !list_empty( d->files ) )
- {
- LIST * files = d->files;
- LISTITER iter = list_begin( files ), end = list_end( files );
- for ( ; iter != end; iter = list_next( iter ) )
- {
- file_info_t * ff = file_info( list_item( iter ) );
- (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
- files = list_next( files );
- }
- }
-
- PROFILE_EXIT( FILE_DIRSCAN );
+ if ( !strcmp( object_str( d->name ), "/" ) )
+ (*func)( closure, d->name, 1 /* stat()'ed */, &d->time );
 }
 
 
-file_info_t * file_query( OBJECT * filename )
-{
- file_info_t * ff = file_info( filename );
- if ( ! ff->time )
- {
- struct stat statbuf;
-
- if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
- return 0;
+/*
+ * file_mkdir() - create a directory
+ */
 
- ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
- ff->is_dir = statbuf.st_mode & S_IFDIR ? 1 : 0;
- ff->size = statbuf.st_size;
- ff->time = statbuf.st_mtime ? statbuf.st_mtime : 1;
- }
- return ff;
+int file_mkdir( char const * const path )
+{
+ /* Explicit cast to remove const modifiers and avoid related compiler
+ * warnings displayed when using the intel compiler.
+ */
+ return mkdir( (char *)path, 0777 );
 }
 
+
 /*
- * file_time() - get timestamp of file, if not done by file_dirscan()
+ * file_query_() - query information about a path from the OS
  */
 
-int
-file_time(
- OBJECT * filename,
- time_t * time )
+void file_query_( file_info_t * const info )
 {
- file_info_t * ff = file_query( filename );
- if ( !ff ) return -1;
- *time = ff->time;
- return 0;
+ file_query_posix_( info );
 }
 
-int file_is_file( OBJECT * filename )
-{
- file_info_t * ff = file_query( filename );
- if ( !ff ) return -1;
- return ff->is_file;
-}
 
-int file_mkdir( const char * pathname )
+/*
+ * file_supported_fmt_resolution() - file modification timestamp resolution
+ *
+ * Returns the minimum file modification timestamp resolution supported by this
+ * Boost Jam implementation. File modification timestamp changes of less than
+ * the returned value might not be recognized.
+ *
+ * Does not take into consideration any OS or file system related restrictions.
+ *
+ * Return value 0 indicates that any value supported by the OS is also supported
+ * here.
+ */
+
+void file_supported_fmt_resolution( timestamp * const t )
 {
- return mkdir( pathname, 0766 );
+ /* The current implementation does not support file modification timestamp
+ * resolution of less than one second.
+ */
+ timestamp_init( t, 1, 0 );
 }
 
+
 /*
  * file_archscan() - scan an archive for files
  */
 
-# ifndef AIAMAG /* God-fearing UNIX */
+#ifndef AIAMAG /* God-fearing UNIX */
 
-# define SARFMAG 2
-# define SARHDR sizeof( struct ar_hdr )
+#define SARFMAG 2
+#define SARHDR sizeof( struct ar_hdr )
 
-void
-file_archscan(
- const char * archive,
- scanback func,
- void * closure )
+void file_archscan( char const * archive, scanback func, void * closure )
 {
-# ifndef NO_AR
+#ifndef NO_AR
     struct ar_hdr ar_hdr;
+ char * string_table = 0;
     char buf[ MAXJPATH ];
     long offset;
- char *string_table = 0;
     int fd;
 
     if ( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
@@ -299,15 +247,15 @@
     if ( DEBUG_BINDSCAN )
         printf( "scan archive %s\n", archive );
 
- while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR )
- && !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
+ while ( ( read( fd, &ar_hdr, SARHDR ) == SARHDR ) &&
+ !( memcmp( ar_hdr.ar_fmag, ARFMAG, SARFMAG )
 #ifdef ARFZMAG
- /* OSF also has a compressed format */
- && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
+ /* OSF also has a compressed format */
+ && memcmp( ar_hdr.ar_fmag, ARFZMAG, SARFMAG )
 #endif
- ) )
+ ) )
     {
- char lar_name_[257];
+ char lar_name_[ 257 ];
         char * lar_name = lar_name_ + 1;
         long lar_date;
         long lar_size;
@@ -315,54 +263,56 @@
         char * c;
         char * src;
         char * dest;
- OBJECT * member;
 
- strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
+ strncpy( lar_name, ar_hdr.ar_name, sizeof( ar_hdr.ar_name ) );
 
         sscanf( ar_hdr.ar_date, "%ld", &lar_date );
         sscanf( ar_hdr.ar_size, "%ld", &lar_size );
 
- if (ar_hdr.ar_name[0] == '/')
- {
- if (ar_hdr.ar_name[1] == '/')
+ if ( ar_hdr.ar_name[ 0 ] == '/' )
         {
- /* this is the "string table" entry of the symbol table,
- ** which holds strings of filenames that are longer than
- ** 15 characters (ie. don't fit into a ar_name
- */
-
- string_table = (char *)BJAM_MALLOC_ATOMIC(lar_size);
- lseek(fd, offset + SARHDR, 0);
- if (read(fd, string_table, lar_size) != lar_size)
- printf("error reading string table\n");
- }
- else if (string_table && ar_hdr.ar_name[1] != ' ')
- {
- /* Long filenames are recognized by "/nnnn" where nnnn is
- ** the offset of the string in the string table represented
- ** in ASCII decimals.
- */
- dest = lar_name;
- lar_offset = atoi(lar_name + 1);
- src = &string_table[lar_offset];
- while (*src != '/')
- *dest++ = *src++;
- *dest = '/';
- }
+ if ( ar_hdr.ar_name[ 1 ] == '/' )
+ {
+ /* This is the "string table" entry of the symbol table, holding
+ * filename strings longer than 15 characters, i.e. those that
+ * do not fit into ar_name.
+ */
+ string_table = (char *)BJAM_MALLOC_ATOMIC( lar_size );
+ lseek( fd, offset + SARHDR, 0 );
+ if ( read( fd, string_table, lar_size ) != lar_size )
+ printf("error reading string table\n");
+ }
+ else if ( string_table && ar_hdr.ar_name[ 1 ] != ' ' )
+ {
+ /* Long filenames are recognized by "/nnnn" where nnnn is the
+ * offset of the string in the string table represented in ASCII
+ * decimals.
+ */
+ dest = lar_name;
+ lar_offset = atoi( lar_name + 1 );
+ src = &string_table[ lar_offset ];
+ while ( *src != '/' )
+ *dest++ = *src++;
+ *dest = '/';
+ }
         }
 
         c = lar_name - 1;
- while ( ( *++c != ' ' ) && ( *c != '/' ) ) ;
+ while ( ( *++c != ' ' ) && ( *c != '/' ) );
         *c = '\0';
 
         if ( DEBUG_BINDSCAN )
- printf( "archive name %s found\n", lar_name );
+ printf( "archive name %s found\n", lar_name );
 
         sprintf( buf, "%s(%s)", archive, lar_name );
 
- member = object_new( buf );
- (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
- object_free( member );
+ {
+ OBJECT * const member = object_new( buf );
+ timestamp time;
+ timestamp_init( &time, (time_t)lar_date, 0 );
+ (*func)( closure, member, 1 /* time valid */, &time );
+ object_free( member );
+ }
 
         offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
         lseek( fd, offset, 0 );
@@ -372,15 +322,13 @@
         BJAM_FREE( string_table );
 
     close( fd );
-
-# endif /* NO_AR */
-
+#endif /* NO_AR */
 }
 
-# else /* AIAMAG - RS6000 AIX */
+#else /* AIAMAG - RS6000 AIX */
 
-static void file_archscan_small(
- int fd, char const *archive, scanback func, void *closure)
+static void file_archscan_small( int fd, char const * archive, scanback func,
+ void * closure )
 {
     struct fl_hdr fl_hdr;
 
@@ -392,7 +340,7 @@
     char buf[ MAXJPATH ];
     long offset;
 
- if ( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ)
+ if ( read( fd, (char *)&fl_hdr, FL_HSZ ) != FL_HSZ )
         return;
 
     sscanf( fl_hdr.fl_fstmoff, "%ld", &offset );
@@ -400,13 +348,11 @@
     if ( DEBUG_BINDSCAN )
         printf( "scan archive %s\n", archive );
 
- while ( ( offset > 0 )
- && ( lseek( fd, offset, 0 ) >= 0 )
- && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) ) )
+ while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 &&
+ read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) )
     {
         long lar_date;
- int lar_namlen;
- OBJECT * member;
+ int lar_namlen;
 
         sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
         sscanf( ar_hdr.hdr.ar_date , "%ld", &lar_date );
@@ -419,17 +365,21 @@
 
         sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
 
- member = object_new( buf );
- (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
- object_free( member );
+ {
+ OBJECT * const member = object_new( buf );
+ timestamp time;
+ timestamp_init( &time, (time_t)lar_date, 0 );
+ (*func)( closure, member, 1 /* time valid */, &time );
+ object_free( member );
+ }
     }
 }
 
-/* Check for OS version which supports the big variant. */
+/* Check for OS versions supporting the big variant. */
 #ifdef AR_HSZ_BIG
 
-static void file_archscan_big(
- int fd, char const *archive, scanback func, void *closure)
+static void file_archscan_big( int fd, char const * archive, scanback func,
+ void * closure )
 {
     struct fl_hdr_big fl_hdr;
 
@@ -441,7 +391,7 @@
     char buf[ MAXJPATH ];
     long long offset;
 
- if ( read( fd, (char *)&fl_hdr, FL_HSZ_BIG) != FL_HSZ_BIG)
+ if ( read( fd, (char *)&fl_hdr, FL_HSZ_BIG ) != FL_HSZ_BIG )
         return;
 
     sscanf( fl_hdr.fl_fstmoff, "%lld", &offset );
@@ -449,13 +399,11 @@
     if ( DEBUG_BINDSCAN )
         printf( "scan archive %s\n", archive );
 
- while ( ( offset > 0 )
- && ( lseek( fd, offset, 0 ) >= 0 )
- && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
+ while ( offset > 0 && lseek( fd, offset, 0 ) >= 0 &&
+ read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) )
     {
         long lar_date;
- int lar_namlen;
- OBJECT * member;
+ int lar_namlen;
 
         sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
         sscanf( ar_hdr.hdr.ar_date , "%ld" , &lar_date );
@@ -468,37 +416,40 @@
 
         sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
 
- member = object_new( buf );
- (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
- object_free( member );
+ {
+ OBJECT * const member = object_new( buf );
+ timestamp time;
+ timestamp_init( &time, (time_t)lar_date, 0 );
+ (*func)( closure, member, 1 /* time valid */, &time );
+ object_free( member );
+ }
     }
-
 }
 
-#endif /* AR_HSZ_BIG */
+#endif /* AR_HSZ_BIG */
 
-void file_archscan( const char * archive, scanback func, void *closure)
+void file_archscan( char const * archive, scanback func, void * closure )
 {
     int fd;
- char fl_magic[SAIAMAG];
+ char fl_magic[ SAIAMAG ];
 
- if (( fd = open( archive, O_RDONLY, 0)) < 0)
+ if ( ( fd = open( archive, O_RDONLY, 0 ) ) < 0 )
         return;
 
- if (read( fd, fl_magic, SAIAMAG) != SAIAMAG
- || lseek(fd, 0, SEEK_SET) == -1)
+ if ( read( fd, fl_magic, SAIAMAG ) != SAIAMAG ||
+ lseek( fd, 0, SEEK_SET ) == -1 )
     {
- close(fd);
+ close( fd );
         return;
     }
 
- if ( strncmp( AIAMAG, fl_magic, SAIAMAG ) == 0 )
+ if ( !strncmp( AIAMAG, fl_magic, SAIAMAG ) )
     {
         /* read small variant */
         file_archscan_small( fd, archive, func, closure );
     }
 #ifdef AR_HSZ_BIG
- else if ( strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) == 0 )
+ else if ( !strncmp( AIAMAGBIG, fl_magic, SAIAMAG ) )
     {
         /* read big variant */
         file_archscan_big( fd, archive, func, closure );
@@ -508,6 +459,6 @@
     close( fd );
 }
 
-# endif /* AIAMAG - RS6000 AIX */
+#endif /* AIAMAG - RS6000 AIX */
 
-# endif /* USE_FILEUNIX */
+#endif /* USE_FILEUNIX */

Modified: branches/release/tools/build/v2/engine/frames.c
==============================================================================
--- branches/release/tools/build/v2/engine/frames.c (original)
+++ branches/release/tools/build/v2/engine/frames.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,20 +4,26 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-# include "frames.h"
-# include "lists.h"
+#include "jam.h"
+#include "frames.h"
 
-void frame_init( FRAME* frame )
+
+FRAME * frame_before_python_call;
+
+
+void frame_init( FRAME * frame )
 {
     frame->prev = 0;
- lol_init(frame->args);
+ frame->prev_user = 0;
+ lol_init( frame->args );
     frame->module = root_module();
     frame->rulename = "module scope";
     frame->file = 0;
     frame->line = -1;
 }
 
-void frame_free( FRAME* frame )
+
+void frame_free( FRAME * frame )
 {
     lol_free( frame->args );
 }

Modified: branches/release/tools/build/v2/engine/frames.h
==============================================================================
--- branches/release/tools/build/v2/engine/frames.h (original)
+++ branches/release/tools/build/v2/engine/frames.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,39 +1,42 @@
 /*
- * Copyright 2001-2004 David Abrahams.
- * 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)
+ * Copyright 2001-2004 David Abrahams.
+ * 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)
  */
+
 #ifndef FRAMES_DWA20011021_H
 #define FRAMES_DWA20011021_H
 
 #include "lists.h"
-#include "object.h"
 #include "modules.h"
+#include "object.h"
+
 
-typedef struct _PARSE PARSE;
 typedef struct frame FRAME;
 
 struct frame
 {
     FRAME * prev;
- /* The nearest enclosing frame for which module->user_module is true. */
- FRAME * prev_user;
+ FRAME * prev_user; /* The nearest enclosing frame for which
+ module->user_module is true. */
     LOL args[ 1 ];
     module_t * module;
     OBJECT * file;
     int line;
- const char * rulename;
+ char const * rulename;
 };
 
 
-/* When call into Python is in progress, this variable points to the bjam frame
- * that was current at the moment of call. When the call completes, the variable
- * is not defined. Further, if Jam calls Python which calls Jam and so on, this
- * variable only keeps the most recent Jam frame.
+/* When a call into Python is in progress, this variable points to the bjam
+ * frame that was current at the moment of the call. When the call completes,
+ * the variable is not defined. Furthermore, if Jam calls Python which calls Jam
+ * and so on, this variable only keeps the most recent Jam frame.
  */
-extern struct frame * frame_before_python_call;
+extern FRAME * frame_before_python_call;
+
 
-void frame_init( FRAME * ); /* implemented in compile.c */
-void frame_free( FRAME * ); /* implemented in compile.c */
+void frame_init( FRAME * );
+void frame_free( FRAME * );
 
 #endif

Modified: branches/release/tools/build/v2/engine/function.c
==============================================================================
--- branches/release/tools/build/v2/engine/function.c (original)
+++ branches/release/tools/build/v2/engine/function.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,119 +1,128 @@
 /*
- * Copyright 2011 Steven Watanabe
- * 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)
+ * Copyright 2011 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)
  */
 
-#include "lists.h"
-#include "pathsys.h"
-#include "mem.h"
-#include "constants.h"
 #include "jam.h"
-#include "frames.h"
 #include "function.h"
-#include "rules.h"
-#include "variable.h"
-#include "compile.h"
-#include "search.h"
+
 #include "class.h"
-#include "pathsys.h"
+#include "compile.h"
+#include "constants.h"
 #include "filesys.h"
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include "frames.h"
+#include "lists.h"
+#include "mem.h"
+#include "pathsys.h"
+#include "rules.h"
+#include "search.h"
+#include "variable.h"
+
 #include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-# ifdef OS_CYGWIN
-# include <sys/cygwin.h>
-# include <windows.h>
+#ifdef OS_CYGWIN
+# include <cygwin/version.h>
+# include <sys/cygwin.h>
+# ifdef CYGWIN_VERSION_CYGWIN_CONV
+# include <errno.h>
 # endif
+# include <windows.h>
+#endif
 
-int glob( const char * s, const char * c );
-void backtrace( FRAME * frame );
-void backtrace_line( FRAME * frame );
-
-#define INSTR_PUSH_EMPTY 0
-#define INSTR_PUSH_CONSTANT 1
-#define INSTR_PUSH_ARG 2
-#define INSTR_PUSH_VAR 3
-#define INSTR_PUSH_VAR_FIXED 57
-#define INSTR_PUSH_GROUP 4
-#define INSTR_PUSH_RESULT 5
-#define INSTR_PUSH_APPEND 6
-#define INSTR_SWAP 7
-
-#define INSTR_JUMP_EMPTY 8
-#define INSTR_JUMP_NOT_EMPTY 9
-
-#define INSTR_JUMP 10
-#define INSTR_JUMP_LT 11
-#define INSTR_JUMP_LE 12
-#define INSTR_JUMP_GT 13
-#define INSTR_JUMP_GE 14
-#define INSTR_JUMP_EQ 15
-#define INSTR_JUMP_NE 16
-#define INSTR_JUMP_IN 17
-#define INSTR_JUMP_NOT_IN 18
-
-#define INSTR_JUMP_NOT_GLOB 19
-
-#define INSTR_FOR_INIT 56
-#define INSTR_FOR_LOOP 20
-
-#define INSTR_SET_RESULT 21
-#define INSTR_RETURN 22
-#define INSTR_POP 23
-
-#define INSTR_PUSH_LOCAL 24
-#define INSTR_POP_LOCAL 25
-#define INSTR_SET 26
-#define INSTR_APPEND 27
-#define INSTR_DEFAULT 28
-
-#define INSTR_PUSH_LOCAL_FIXED 58
-#define INSTR_POP_LOCAL_FIXED 59
-#define INSTR_SET_FIXED 60
-#define INSTR_APPEND_FIXED 61
-#define INSTR_DEFAULT_FIXED 62
-
-#define INSTR_PUSH_LOCAL_GROUP 29
-#define INSTR_POP_LOCAL_GROUP 30
-#define INSTR_SET_GROUP 31
-#define INSTR_APPEND_GROUP 32
-#define INSTR_DEFAULT_GROUP 33
-
-#define INSTR_PUSH_ON 34
-#define INSTR_POP_ON 35
-#define INSTR_SET_ON 36
-#define INSTR_APPEND_ON 37
-#define INSTR_DEFAULT_ON 38
-
-#define INSTR_CALL_RULE 39
-
-#define INSTR_APPLY_MODIFIERS 40
-#define INSTR_APPLY_INDEX 41
-#define INSTR_APPLY_INDEX_MODIFIERS 42
-#define INSTR_APPLY_MODIFIERS_GROUP 43
-#define INSTR_APPLY_INDEX_GROUP 44
-#define INSTR_APPLY_INDEX_MODIFIERS_GROUP 45
-#define INSTR_COMBINE_STRINGS 46
-
-#define INSTR_INCLUDE 47
-#define INSTR_RULE 48
-#define INSTR_ACTIONS 49
-#define INSTR_PUSH_MODULE 50
-#define INSTR_POP_MODULE 51
-#define INSTR_CLASS 52
-#define INSTR_BIND_MODULE_VARIABLES 63
-
-#define INSTR_APPEND_STRINGS 53
-#define INSTR_WRITE_FILE 54
-#define INSTR_OUTPUT_STRINGS 55
+int glob( char const * s, char const * c );
+void backtrace( FRAME * );
+void backtrace_line( FRAME * );
+
+#define INSTR_PUSH_EMPTY 0
+#define INSTR_PUSH_CONSTANT 1
+#define INSTR_PUSH_ARG 2
+#define INSTR_PUSH_VAR 3
+#define INSTR_PUSH_VAR_FIXED 57
+#define INSTR_PUSH_GROUP 4
+#define INSTR_PUSH_RESULT 5
+#define INSTR_PUSH_APPEND 6
+#define INSTR_SWAP 7
+
+#define INSTR_JUMP_EMPTY 8
+#define INSTR_JUMP_NOT_EMPTY 9
+
+#define INSTR_JUMP 10
+#define INSTR_JUMP_LT 11
+#define INSTR_JUMP_LE 12
+#define INSTR_JUMP_GT 13
+#define INSTR_JUMP_GE 14
+#define INSTR_JUMP_EQ 15
+#define INSTR_JUMP_NE 16
+#define INSTR_JUMP_IN 17
+#define INSTR_JUMP_NOT_IN 18
+
+#define INSTR_JUMP_NOT_GLOB 19
+
+#define INSTR_FOR_INIT 56
+#define INSTR_FOR_LOOP 20
+
+#define INSTR_SET_RESULT 21
+#define INSTR_RETURN 22
+#define INSTR_POP 23
+
+#define INSTR_PUSH_LOCAL 24
+#define INSTR_POP_LOCAL 25
+#define INSTR_SET 26
+#define INSTR_APPEND 27
+#define INSTR_DEFAULT 28
+
+#define INSTR_PUSH_LOCAL_FIXED 58
+#define INSTR_POP_LOCAL_FIXED 59
+#define INSTR_SET_FIXED 60
+#define INSTR_APPEND_FIXED 61
+#define INSTR_DEFAULT_FIXED 62
+
+#define INSTR_PUSH_LOCAL_GROUP 29
+#define INSTR_POP_LOCAL_GROUP 30
+#define INSTR_SET_GROUP 31
+#define INSTR_APPEND_GROUP 32
+#define INSTR_DEFAULT_GROUP 33
+
+#define INSTR_PUSH_ON 34
+#define INSTR_POP_ON 35
+#define INSTR_SET_ON 36
+#define INSTR_APPEND_ON 37
+#define INSTR_DEFAULT_ON 38
+#define INSTR_GET_ON 65
+
+#define INSTR_CALL_RULE 39
+#define INSTR_CALL_MEMBER_RULE 66
+
+#define INSTR_APPLY_MODIFIERS 40
+#define INSTR_APPLY_INDEX 41
+#define INSTR_APPLY_INDEX_MODIFIERS 42
+#define INSTR_APPLY_MODIFIERS_GROUP 43
+#define INSTR_APPLY_INDEX_GROUP 44
+#define INSTR_APPLY_INDEX_MODIFIERS_GROUP 45
+#define INSTR_COMBINE_STRINGS 46
+#define INSTR_GET_GRIST 64
+
+#define INSTR_INCLUDE 47
+#define INSTR_RULE 48
+#define INSTR_ACTIONS 49
+#define INSTR_PUSH_MODULE 50
+#define INSTR_POP_MODULE 51
+#define INSTR_CLASS 52
+#define INSTR_BIND_MODULE_VARIABLES 63
+
+#define INSTR_APPEND_STRINGS 53
+#define INSTR_WRITE_FILE 54
+#define INSTR_OUTPUT_STRINGS 55
 
 typedef struct instruction
 {
     unsigned int op_code;
- int arg;
+ int arg;
 } instruction;
 
 typedef struct _subfunction
@@ -125,15 +134,16 @@
 
 typedef struct _subaction
 {
- OBJECT * name;
+ OBJECT * name;
     FUNCTION * command;
- int flags;
+ int flags;
 } SUBACTION;
 
 #define FUNCTION_BUILTIN 0
 #define FUNCTION_JAM 1
 
-struct argument {
+struct argument
+{
     int flags;
 #define ARG_ONE 0
 #define ARG_OPTIONAL 1
@@ -145,7 +155,8 @@
     int index;
 };
 
-struct arg_list {
+struct arg_list
+{
     int size;
     struct argument * args;
 };
@@ -193,7 +204,7 @@
     PyObject * python_function;
 } PYTHON_FUNCTION;
 
-static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame );
+static LIST * call_python_function( PYTHON_FUNCTION *, FRAME * );
 
 #endif
 
@@ -210,7 +221,7 @@
     static STACK result;
     if ( !stack )
     {
- int size = 1 << 21;
+ int const size = 1 << 21;
         stack = BJAM_MALLOC( size );
         result.data = (char *)stack + size;
     }
@@ -219,7 +230,7 @@
 
 static void check_alignment( STACK * s )
 {
- assert( (unsigned long)s->data % sizeof( LIST * ) == 0 );
+ assert( (size_t)s->data % sizeof( LIST * ) == 0 );
 }
 
 void * stack_allocate( STACK * s, int size )
@@ -244,12 +255,12 @@
 
 LIST * stack_pop( STACK * s )
 {
- LIST * result = *(LIST * *)s->data;
+ LIST * const result = *(LIST * *)s->data;
     stack_deallocate( s, sizeof( LIST * ) );
     return result;
 }
 
-LIST * stack_top(STACK * s)
+LIST * stack_top( STACK * s )
 {
     check_alignment( s );
     return *(LIST * *)s->data;
@@ -258,7 +269,7 @@
 LIST * stack_at( STACK * s, int n )
 {
     check_alignment( s );
- return *((LIST * *)s->data + n);
+ return *( (LIST * *)s->data + n );
 }
 
 void stack_set( STACK * s, int n, LIST * value )
@@ -270,12 +281,12 @@
 void * stack_get( STACK * s )
 {
     check_alignment( s );
- return (LIST * *)s->data;
+ return s->data;
 }
 
 LIST * frame_get_local( FRAME * frame, int idx )
 {
- /* The only local variables are the arguments */
+ /* The only local variables are the arguments. */
     return list_copy( lol_get( frame->args, idx ) );
 }
 
@@ -284,55 +295,63 @@
     return function->constants[ idx ];
 }
 
-static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame, int idx )
+static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame,
+ int idx )
 {
- return list_copy( var_get( frame->module, function->constants[idx] ) );
+ return list_copy( var_get( frame->module, function->constants[ idx ] ) );
 }
 
-static void function_set_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+static void function_set_variable( JAM_FUNCTION * function, FRAME * frame,
+ int idx, LIST * value )
 {
- var_set( frame->module, function->constants[idx], value, VAR_SET );
+ var_set( frame->module, function->constants[ idx ], value, VAR_SET );
 }
 
-static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame,
+ int idx, LIST * value )
 {
- return var_swap( frame->module, function->constants[idx], value );
+ return var_swap( frame->module, function->constants[ idx ], value );
 }
 
-static void function_append_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+static void function_append_variable( JAM_FUNCTION * function, FRAME * frame,
+ int idx, LIST * value )
 {
- var_set( frame->module, function->constants[idx], value, VAR_APPEND );
+ var_set( frame->module, function->constants[ idx ], value, VAR_APPEND );
 }
 
-static void function_default_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+static void function_default_variable( JAM_FUNCTION * function, FRAME * frame,
+ int idx, LIST * value )
 {
- var_set( frame->module, function->constants[idx], value, VAR_DEFAULT );
+ var_set( frame->module, function->constants[ idx ], value, VAR_DEFAULT );
 }
 
-static void function_set_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+static void function_set_rule( JAM_FUNCTION * function, FRAME * frame,
+ STACK * s, int idx )
 {
     SUBFUNCTION * sub = function->functions + idx;
     new_rule_body( frame->module, sub->name, sub->code, !sub->local );
 }
 
-static void function_set_actions( JAM_FUNCTION * function, FRAME * frame, STACK * s, int idx )
+static void function_set_actions( JAM_FUNCTION * function, FRAME * frame,
+ STACK * s, int idx )
 {
     SUBACTION * sub = function->actions + idx;
     LIST * bindlist = stack_pop( s );
-
- new_rule_actions( frame->module, sub->name, sub->command, bindlist, sub->flags );
+ new_rule_actions( frame->module, sub->name, sub->command, bindlist,
+ sub->flags );
 }
 
+
 /*
- * returns the index if name is "<", ">", "1", "2", ... or "19"
- * otherwise returns -1.
+ * Returns the index if name is "<", ">", "1", "2", ... or "19" otherwise
+ * returns -1.
  */
 
-static int get_argument_index( const char * s )
+static int get_argument_index( char const * s )
 {
- if( s[ 0 ] != '\0')
+ if ( s[ 0 ] != '\0')
     {
- if( s[ 1 ] == '\0' )
+ if ( s[ 1 ] == '\0' )
         {
             switch ( s[ 0 ] )
             {
@@ -372,42 +391,43 @@
     return -1;
 }
 
-static LIST * function_get_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name )
+static LIST * function_get_named_variable( JAM_FUNCTION * function,
+ FRAME * frame, OBJECT * name )
 {
- int idx = get_argument_index( object_str( name ) );
- if( idx != -1 )
- {
- return list_copy( lol_get( frame->args, idx ) );
- }
- else
- {
- return list_copy( var_get( frame->module, name ) );
- }
+ int const idx = get_argument_index( object_str( name ) );
+ return idx == -1
+ ? list_copy( var_get( frame->module, name ) )
+ : list_copy( lol_get( frame->args, idx ) );
 }
 
-static void function_set_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+static void function_set_named_variable( JAM_FUNCTION * function, FRAME * frame,
+ OBJECT * name, LIST * value)
 {
     var_set( frame->module, name, value, VAR_SET );
 }
 
-static LIST * function_swap_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+static LIST * function_swap_named_variable( JAM_FUNCTION * function,
+ FRAME * frame, OBJECT * name, LIST * value )
 {
     return var_swap( frame->module, name, value );
 }
 
-static void function_append_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value)
+static void function_append_named_variable( JAM_FUNCTION * function,
+ FRAME * frame, OBJECT * name, LIST * value)
 {
     var_set( frame->module, name, value, VAR_APPEND );
 }
 
-static void function_default_named_variable( JAM_FUNCTION * function, FRAME * frame, OBJECT * name, LIST * value )
+static void function_default_named_variable( JAM_FUNCTION * function,
+ FRAME * frame, OBJECT * name, LIST * value )
 {
     var_set( frame->module, name, value, VAR_DEFAULT );
 }
 
-static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, const char * unexpanded, OBJECT * file, int line )
+static LIST * function_call_rule( JAM_FUNCTION * function, FRAME * frame,
+ STACK * s, int n_args, char const * unexpanded, OBJECT * file, int line )
 {
- FRAME inner[ 1 ];
+ FRAME inner[ 1 ];
     int i;
     LIST * first = stack_pop( s );
     LIST * result = L0;
@@ -416,12 +436,68 @@
 
     frame->file = file;
     frame->line = line;
-
+
     if ( list_empty( first ) )
     {
         backtrace_line( frame );
         printf( "warning: rulename %s expands to empty string\n", unexpanded );
         backtrace( frame );
+ list_free( first );
+ for ( i = 0; i < n_args; ++i )
+ list_free( stack_pop( s ) );
+ return result;
+ }
+
+ rulename = object_copy( list_front( first ) );
+
+ frame_init( inner );
+ inner->prev = frame;
+ inner->prev_user = frame->module->user_module ? frame : frame->prev_user;
+ inner->module = frame->module; /* This gets fixed up in evaluate_rule(). */
+
+ for ( i = 0; i < n_args; ++i )
+ lol_add( inner->args, stack_at( s, n_args - i - 1 ) );
+
+ for ( i = 0; i < n_args; ++i )
+ stack_pop( s );
+
+ trailing = list_pop_front( first );
+ if ( trailing )
+ {
+ if ( inner->args->count == 0 )
+ lol_add( inner->args, trailing );
+ else
+ {
+ LIST * * const l = &inner->args->list[ 0 ];
+ *l = list_append( trailing, *l );
+ }
+ }
+
+ result = evaluate_rule( bindrule( rulename, inner->module ), rulename, inner );
+ frame_free( inner );
+ object_free( rulename );
+ return result;
+}
+
+static LIST * function_call_member_rule( JAM_FUNCTION * function, FRAME * frame, STACK * s, int n_args, OBJECT * rulename, OBJECT * file, int line )
+{
+ FRAME inner[ 1 ];
+ int i;
+ LIST * first = stack_pop( s );
+ LIST * result = L0;
+ LIST * trailing;
+ RULE * rule;
+ module_t * module;
+ OBJECT * real_rulename = 0;
+
+ frame->file = file;
+ frame->line = line;
+
+ if ( list_empty( first ) )
+ {
+ backtrace_line( frame );
+ printf( "warning: object is empty\n" );
+ backtrace( frame );
 
         list_free( first );
 
@@ -433,7 +509,26 @@
         return result;
     }
 
- rulename = object_copy( list_front( first ) );
+ /* FIXME: handle generic case */
+ assert( list_length( first ) == 1 );
+
+ module = bindmodule( list_front( first ) );
+ if ( module->class_module )
+ {
+ rule = bindrule( rulename, module );
+ real_rulename = object_copy( function_rulename( rule->procedure ) );
+ }
+ else
+ {
+ string buf[ 1 ];
+ string_new( buf );
+ string_append( buf, object_str( list_front( first ) ) );
+ string_push_back( buf, '.' );
+ string_append( buf, object_str( rulename ) );
+ real_rulename = object_new( buf->value );
+ string_free( buf );
+ rule = bindrule( real_rulename, frame->module );
+ }
 
     frame_init( inner );
 
@@ -451,26 +546,39 @@
         stack_pop( s );
     }
 
- trailing = list_pop_front( first );
- if ( trailing )
+ if ( list_length( first ) > 1 )
     {
- if ( inner->args->count == 0 )
+ string buf[ 1 ];
+ LIST * trailing = L0;
+ LISTITER iter = list_begin( first ), end = list_end( first );
+ iter = list_next( iter );
+ string_new( buf );
+ for ( ; iter != end; iter = list_next( iter ) )
         {
- lol_add( inner->args, trailing );
+ string_append( buf, object_str( list_item( iter ) ) );
+ string_push_back( buf, '.' );
+ string_append( buf, object_str( rulename ) );
+ trailing = list_push_back( trailing, object_new( buf->value ) );
+ string_truncate( buf, 0 );
         }
+ string_free( buf );
+ if ( inner->args->count == 0 )
+ lol_add( inner->args, trailing );
         else
         {
- LIST * * l = &inner->args->list[0];
+ LIST * * const l = &inner->args->list[ 0 ];
             *l = list_append( trailing, *l );
         }
     }
 
- result = evaluate_rule( rulename, inner );
+ result = evaluate_rule( rule, real_rulename, inner );
     frame_free( inner );
     object_free( rulename );
+ object_free( real_rulename );
     return result;
 }
 
+
 /* Variable expansion */
 
 typedef struct
@@ -492,11 +600,10 @@
     PATHPART join; /* :J -- join list with char */
 } VAR_EDITS;
 
-static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER iter, LISTITER end );
-static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length );
-static void var_edit_file( const char * in, string * out, VAR_EDITS * edits );
-static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits );
-static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed );
+static LIST * apply_modifiers_impl( LIST * result, string * buf,
+ VAR_EDITS * edits, int n, LISTITER iter, LISTITER end );
+static void get_iters( subscript_t const subscript, LISTITER * const first,
+ LISTITER * const last, int const length );
 
 
 /*
@@ -534,7 +641,8 @@
  * var_edit_file() below and path_build() obligingly follow this convention.
  */
 
-static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed )
+static int var_edit_parse( char const * mods, VAR_EDITS * edits, int havezeroed
+ )
 {
     while ( *mods )
     {
@@ -601,11 +709,12 @@
     return havezeroed;
 }
 
+
 /*
  * var_edit_file() - copy input target name to output, modifying filename.
  */
 
-static void var_edit_file( const char * in, string * out, VAR_EDITS * edits )
+static void var_edit_file( char const * in, string * out, VAR_EDITS * edits )
 {
     if ( edits->filemods )
     {
@@ -627,37 +736,97 @@
             path_parent( &pathname );
 
         /* Put filename back together. */
- path_build( &pathname, out, 0 );
+ path_build( &pathname, out );
     }
     else
- {
         string_append( out, in );
- }
 }
 
 /*
- * var_edit_shift() - do upshift/downshift mods.
+ * var_edit_cyg2win() - conversion of a cygwin to a Windows path.
+ *
+ * FIXME: skip grist
  */
 
-static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
+#ifdef OS_CYGWIN
+static void var_edit_cyg2win( string * out, size_t pos, VAR_EDITS * edits )
 {
- if ( edits->upshift || edits->downshift || edits->to_windows || edits->to_slashes )
+ if ( edits->to_windows )
     {
- /* Handle upshifting, downshifting and slash translation now. */
- char * p;
-# ifdef OS_CYGWIN
- if ( edits->to_windows )
+ #ifdef CYGWIN_VERSION_CYGWIN_CONV
+ /* Use new Cygwin API added with Cygwin 1.7. Old one had no error
+ * handling and has been deprecated.
+ */
+ char * dynamicBuffer = 0;
+ char buffer[ MAX_PATH + 1001 ];
+ char const * result = buffer;
+ cygwin_conv_path_t const conv_type = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
+ ssize_t const apiResult = cygwin_conv_path( conv_type, out->value + pos,
+ buffer, sizeof( buffer ) / sizeof( *buffer ) );
+ assert( apiResult == 0 || apiResult == -1 );
+ assert( apiResult || strlen( result ) < sizeof( buffer ) / sizeof(
+ *buffer ) );
+ if ( apiResult )
+ {
+ result = 0;
+ if ( errno == ENOSPC )
+ {
+ ssize_t const size = cygwin_conv_path( conv_type, out->value +
+ pos, NULL, 0 );
+ assert( size >= -1 );
+ if ( size > 0 )
+ {
+ dynamicBuffer = (char *)BJAM_MALLOC_ATOMIC( size );
+ if ( dynamicBuffer )
+ {
+ ssize_t const apiResult = cygwin_conv_path( conv_type,
+ out->value + pos, dynamicBuffer, size );
+ assert( apiResult == 0 || apiResult == -1 );
+ if ( !apiResult )
+ {
+ result = dynamicBuffer;
+ assert( strlen( result ) < size );
+ }
+ }
+ }
+ }
+ }
+ #else /* CYGWIN_VERSION_CYGWIN_CONV */
+ /* Use old Cygwin API deprecated with Cygwin 1.7. */
+ char result[ MAX_PATH + 1 ];
+ cygwin_conv_to_win32_path( out->value + pos, result );
+ assert( strlen( result ) <= MAX_PATH );
+ #endif /* CYGWIN_VERSION_CYGWIN_CONV */
+ if ( result )
         {
- /* FIXME: skip grist */
- char result[ MAX_PATH + 1 ];
- cygwin_conv_to_win32_path( out->value + pos, result );
- assert( strlen( result ) <= MAX_PATH );
             string_truncate( out, pos );
             string_append( out, result );
             edits->to_slashes = 0;
         }
-# endif
- for ( p = out->value + pos; *p; ++p)
+ #ifdef CYGWIN_VERSION_CYGWIN_CONV
+ if ( dynamicBuffer )
+ BJAM_FREE( dynamicBuffer );
+ #endif
+ }
+}
+#endif /* OS_CYGWIN */
+
+
+/*
+ * var_edit_shift() - do upshift/downshift & other mods.
+ */
+
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
+{
+#ifdef OS_CYGWIN
+ var_edit_cyg2win( out, pos, edits );
+#endif
+
+ if ( edits->upshift || edits->downshift || edits->to_slashes )
+ {
+ /* Handle upshifting, downshifting and slash translation now. */
+ char * p;
+ for ( p = out->value + pos; *p; ++p )
         {
             if ( edits->upshift )
                 *p = toupper( *p );
@@ -669,12 +838,10 @@
     }
 }
 
+
 /*
- * Reads n LISTs from the top of the STACK and
- * combines them to form VAR_EDITS.
- *
- * returns the number of VAR_EDITS pushed onto
- * the STACK.
+ * Reads n LISTs from the top of the STACK and combines them to form VAR_EDITS.
+ * Returns the number of VAR_EDITS pushed onto the STACK.
  */
 
 static int expand_modifiers( STACK * s, int n )
@@ -682,39 +849,33 @@
     int i;
     int total = 1;
     LIST * * args = stack_get( s );
- for( i = 0; i < n; ++i)
- total *= list_length( args[i] );
+ for ( i = 0; i < n; ++i )
+ total *= list_length( args[ i ] );
 
     if ( total != 0 )
     {
- VAR_EDITS * out = stack_allocate( s, total * sizeof(VAR_EDITS) );
- LISTITER * iter = stack_allocate( s, n * sizeof(LIST *) );
- for (i = 0; i < n; ++i )
- {
- iter[i] = list_begin( args[i] );
- }
+ VAR_EDITS * out = stack_allocate( s, total * sizeof( VAR_EDITS ) );
+ LISTITER * iter = stack_allocate( s, n * sizeof( LIST * ) );
+ for ( i = 0; i < n; ++i )
+ iter[ i ] = list_begin( args[ i ] );
         i = 0;
         {
             int havezeroed;
         loop:
             memset( out, 0, sizeof( *out ) );
             havezeroed = 0;
- for (i = 0; i < n; ++i )
- {
- havezeroed = var_edit_parse( object_str( list_item( iter[i] ) ), out, havezeroed );
- }
+ for ( i = 0; i < n; ++i )
+ havezeroed = var_edit_parse( object_str( list_item( iter[ i ] )
+ ), out, havezeroed );
             ++out;
             while ( --i >= 0 )
             {
- if ( list_next( iter[i] ) != list_end( args[i] ) )
+ if ( list_next( iter[ i ] ) != list_end( args[ i ] ) )
                 {
- iter[i] = list_next( iter[i] );
+ iter[ i ] = list_next( iter[ i ] );
                     goto loop;
                 }
- else
- {
- iter[i] = list_begin( args[i] );
- }
+ iter[ i ] = list_begin( args[ i ] );
             }
         }
         stack_deallocate( s, n * sizeof( LIST * ) );
@@ -726,20 +887,22 @@
 {
     LIST * value = stack_top( s );
     LIST * result = L0;
- VAR_EDITS * edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 );
- string buf[1];
+ VAR_EDITS * const edits = (VAR_EDITS *)( (LIST * *)stack_get( s ) + 1 );
+ string buf[ 1 ];
     string_new( buf );
- result = apply_modifiers_impl( result, buf, edits, n, list_begin( value ), list_end( value ) );
+ result = apply_modifiers_impl( result, buf, edits, n, list_begin( value ),
+ list_end( value ) );
     string_free( buf );
     return result;
 }
 
+
 /*
- * Parse a string of the form "1-2", "-2--1", "2-"
- * and return the two subscripts.
+ * Parse a string of the form "1-2", "-2--1", "2-" and return the two
+ * subscripts.
  */
 
-subscript_t parse_subscript( const char * s )
+subscript_t parse_subscript( char const * s )
 {
     subscript_t result;
     result.sub1 = 0;
@@ -801,30 +964,33 @@
     LIST * indices = stack_at( s, 1 );
     LIST * result = L0;
     int length = list_length( value );
- string buf[1];
- LISTITER indices_iter = list_begin( indices ), indices_end = list_end( indices );
+ string buf[ 1 ];
+ LISTITER indices_iter = list_begin( indices );
+ LISTITER const indices_end = list_end( indices );
     string_new( buf );
- for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter ) )
+ for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter
+ ) )
     {
         LISTITER iter = list_begin( value );
         LISTITER end = list_end( value );
- subscript_t subscript = parse_subscript( object_str( list_item( indices_iter ) ) );
+ subscript_t const subscript = parse_subscript( object_str( list_item(
+ indices_iter ) ) );
         get_iters( subscript, &iter, &end, length );
         for ( ; iter != end; iter = list_next( iter ) )
- {
             result = list_push_back( result, object_copy( list_item( iter ) ) );
- }
     }
     string_free( buf );
     return result;
 }
 
+
 /*
- * Reads the LIST from first and applies subscript to it.
- * The results are written to *first and *last.
+ * Reads the LIST from first and applies subscript to it. The results are
+ * written to *first and *last.
  */
 
-static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length )
+static void get_iters( subscript_t const subscript, LISTITER * const first,
+ LISTITER * const last, int const length )
 {
     int start;
     int size;
@@ -834,28 +1000,24 @@
 
         if ( subscript.sub1 < 0 )
             start = length + subscript.sub1;
- else if( subscript.sub1 > length )
+ else if ( subscript.sub1 > length )
             start = length;
         else
             start = subscript.sub1 - 1;
 
- if ( subscript.sub2 < 0 )
- size = length + 1 + subscript.sub2 - start;
- else
- size = subscript.sub2 - start;
+ size = subscript.sub2 < 0
+ ? length + 1 + subscript.sub2 - start
+ : subscript.sub2 - start;
 
         /*
- * HACK: When the first subscript is before the start of the
- * list, it magically becomes the beginning of the list.
- * This is inconsistent, but needed for backwards
- * compatibility.
+ * HACK: When the first subscript is before the start of the list, it
+ * magically becomes the beginning of the list. This is inconsistent,
+ * but needed for backwards compatibility.
          */
         if ( start < 0 )
             start = 0;
 
- /* The "sub2 < 0" test handles the semantic error of sub2 <
- * sub1.
- */
+ /* The "sub2 < 0" test handles the semantic error of sub2 < sub1. */
         if ( size < 0 )
             size = 0;
 
@@ -875,15 +1037,16 @@
     *last = end;
 }
 
-static LIST * apply_modifiers_empty( LIST * result, string * buf, VAR_EDITS * edits, int n)
+static LIST * apply_modifiers_empty( LIST * result, string * buf,
+ VAR_EDITS * edits, int n )
 {
     int i;
     for ( i = 0; i < n; ++i )
     {
- if ( edits[i].empty.ptr )
+ if ( edits[ i ].empty.ptr )
         {
             /** FIXME: is empty.ptr always null-terminated? */
- var_edit_file( edits[i].empty.ptr, buf, edits + i );
+ var_edit_file( edits[ i ].empty.ptr, buf, edits + i );
             var_edit_shift( buf, 0, edits + i );
             result = list_push_back( result, object_new( buf->value ) );
             string_truncate( buf, 0 );
@@ -892,22 +1055,25 @@
     return result;
 }
 
-static LIST * apply_modifiers_non_empty( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER begin, LISTITER end )
+static LIST * apply_modifiers_non_empty( LIST * result, string * buf,
+ VAR_EDITS * edits, int n, LISTITER begin, LISTITER end )
 {
     int i;
     LISTITER iter;
     for ( i = 0; i < n; ++i )
     {
- if ( edits[i].join.ptr )
+ if ( edits[ i ].join.ptr )
         {
             var_edit_file( object_str( list_item( begin ) ), buf, edits + i );
             var_edit_shift( buf, 0, edits + i );
- for ( iter = list_next( begin ); iter != end; iter = list_next( iter ) )
+ for ( iter = list_next( begin ); iter != end; iter = list_next( iter
+ ) )
             {
                 size_t size;
- string_append( buf, edits[i].join.ptr );
+ string_append( buf, edits[ i ].join.ptr );
                 size = buf->size;
- var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
+ var_edit_file( object_str( list_item( iter ) ), buf, edits + i
+ );
                 var_edit_shift( buf, size, edits + i );
             }
             result = list_push_back( result, object_new( buf->value ) );
@@ -927,33 +1093,32 @@
     return result;
 }
 
-static LIST * apply_modifiers_impl( LIST * result, string * buf, VAR_EDITS * edits, int n, LISTITER iter, LISTITER end )
+static LIST * apply_modifiers_impl( LIST * result, string * buf,
+ VAR_EDITS * edits, int n, LISTITER iter, LISTITER end )
 {
- if ( iter != end )
- {
- return apply_modifiers_non_empty( result, buf, edits, n, iter, end );
- }
- else
- {
- return apply_modifiers_empty( result, buf, edits, n );
- }
+ return iter == end
+ ? apply_modifiers_empty( result, buf, edits, n )
+ : apply_modifiers_non_empty( result, buf, edits, n, iter, end );
 }
 
 static LIST * apply_subscript_and_modifiers( STACK * s, int n )
 {
- LIST * value = stack_top( s );
- LIST * indices = stack_at( s, 1 );
+ LIST * const value = stack_top( s );
+ LIST * const indices = stack_at( s, 1 );
     LIST * result = L0;
- VAR_EDITS * edits = (VAR_EDITS *)((LIST * *)stack_get( s ) + 2);
- int length = list_length( value );
- string buf[1];
- LISTITER indices_iter = list_begin( indices ), indices_end = list_end( indices );
+ VAR_EDITS * const edits = (VAR_EDITS *)((LIST * *)stack_get( s ) + 2);
+ int const length = list_length( value );
+ string buf[ 1 ];
+ LISTITER indices_iter = list_begin( indices );
+ LISTITER const indices_end = list_end( indices );
     string_new( buf );
- for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter ) )
+ for ( ; indices_iter != indices_end; indices_iter = list_next( indices_iter
+ ) )
     {
         LISTITER iter = list_begin( value );
         LISTITER end = list_end( value );
- subscript_t sub = parse_subscript( object_str( list_item( indices_iter ) ) );
+ subscript_t const sub = parse_subscript( object_str( list_item(
+ indices_iter ) ) );
         get_iters( sub, &iter, &end, length );
         result = apply_modifiers_impl( result, buf, edits, n, iter, end );
     }
@@ -961,57 +1126,116 @@
     return result;
 }
 
+
+/*
+ * expand() - expands a list of concatenated strings and variable refereces
+ *
+ * Takes a list of expansion items - each representing one element to be
+ * concatenated and each containing a list of its values. Returns a list of all
+ * possible values constructed by selecting a single value from each of the
+ * elements and concatenating them together.
+ *
+ * For example, in the following code:
+ *
+ * local a = one two three four ;
+ * local b = foo bar ;
+ * ECHO /$(a)/$(b)/$(a)/ ;
+ *
+ * When constructing the result of /$(a)/$(b)/ this function would get called
+ * with the following 7 expansion items:
+ * 1. /
+ * 2. one two three four
+ * 3. /
+ * 4. foo bar
+ * 5. /
+ * 6. one two three four
+ * 7. /
+ *
+ * And would result in a list containing 32 values:
+ * 1. /one/foo/one/
+ * 2. /one/foo/two/
+ * 3. /one/foo/three/
+ * 4. /one/foo/four/
+ * 5. /one/bar/one/
+ * ...
+ *
+ */
+
 typedef struct expansion_item
 {
- LISTITER elem;
- LIST * saved;
- int size;
+ /* Item's value list initialized prior to calling expand(). */
+ LIST * values;
+
+ /* Internal data initialized and used inside expand(). */
+ LISTITER current; /* Currently used value. */
+ int size; /* Concatenated string length prior to concatenating the
+ * item's current value.
+ */
 } expansion_item;
 
-static LIST * expand( expansion_item * elem, int length )
+static LIST * expand( expansion_item * items, int const length )
 {
     LIST * result = L0;
- string buf[1];
+ string buf[ 1 ];
     int size = 0;
     int i;
+
     assert( length > 0 );
     for ( i = 0; i < length; ++i )
     {
- int max = 0;
- LISTITER iter = elem[i].elem, end = list_end( elem[i].saved );
- if ( iter == end ) return result;
- for ( ; iter != end; iter = list_next( iter ) )
+ LISTITER iter = list_begin( items[ i ].values );
+ LISTITER const end = list_end( items[ i ].values );
+
+ /* If any of the items has no values - the result is an empty list. */
+ if ( iter == end ) return L0;
+
+ /* Set each item's 'current' to its first listed value. This indicates
+ * each item's next value to be used when constructing the list of all
+ * possible concatenated values.
+ */
+ items[ i ].current = iter;
+
+ /* Calculate the longest concatenated string length - to know how much
+ * memory we need to allocate as a buffer for holding the concatenated
+ * strings.
+ */
         {
- int len = strlen( object_str( list_item( iter ) ) );
- if ( len > max ) max = len;
+ int max = 0;
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ int const len = strlen( object_str( list_item( iter ) ) );
+ if ( len > max ) max = len;
+ }
+ size += max;
         }
- size += max;
     }
+
     string_new( buf );
     string_reserve( buf, size );
+
     i = 0;
+ while ( i >= 0 )
     {
- loop:
         for ( ; i < length; ++i )
         {
- elem[i].size = buf->size;
- string_append( buf, object_str( list_item( elem[i].elem ) ) );
+ items[ i ].size = buf->size;
+ string_append( buf, object_str( list_item( items[ i ].current ) ) );
         }
         result = list_push_back( result, object_new( buf->value ) );
         while ( --i >= 0 )
         {
- if( list_next( elem[i].elem ) != list_end( elem[i].saved ) )
+ if ( list_next( items[ i ].current ) != list_end( items[ i ].values
+ ) )
             {
- elem[i].elem = list_next( elem[i].elem );
- string_truncate( buf, elem[i].size );
- goto loop;
+ items[ i ].current = list_next( items[ i ].current );
+ string_truncate( buf, items[ i ].size );
+ break;
             }
             else
- {
- elem[i].elem = list_begin( elem[i].saved );
- }
+ items[ i ].current = list_begin( items[ i ].values );
         }
     }
+
     string_free( buf );
     return result;
 }
@@ -1021,12 +1245,14 @@
     int i;
     for ( i = 0; i < n; ++i )
     {
- LIST * values = stack_pop( s );
- LISTITER iter = list_begin( values ), end = list_end( values );
+ LIST * const values = stack_pop( s );
+ LISTITER iter = list_begin( values );
+ LISTITER const end = list_end( values );
         if ( iter != end )
         {
             string_append( out, object_str( list_item( iter ) ) );
- for ( iter = list_next( iter ); iter != end; iter = list_next( iter ) )
+ for ( iter = list_next( iter ); iter != end; iter = list_next( iter
+ ) )
             {
                 string_push_back( out, ' ' );
                 string_append( out, object_str( list_item( iter ) ) );
@@ -1055,7 +1281,8 @@
     BJAM_FREE( array->data );
 }
 
-static void dynamic_array_push_impl( struct dynamic_array * array, void * value, int unit_size )
+static void dynamic_array_push_impl( struct dynamic_array * const array,
+ void const * const value, int const unit_size )
 {
     if ( array->capacity == 0 )
     {
@@ -1075,9 +1302,10 @@
     ++array->size;
 }
 
-#define dynamic_array_push( array, value ) ( dynamic_array_push_impl( array, &value, sizeof(value) ) )
+#define dynamic_array_push( array, value ) (dynamic_array_push_impl(array, &value, sizeof(value)))
 #define dynamic_array_at( type, array, idx ) (((type *)(array)->data)[idx])
 
+
 /*
  * struct compiler
  */
@@ -1085,7 +1313,7 @@
 struct label_info
 {
     int absolute_position;
- struct dynamic_array uses[1];
+ struct dynamic_array uses[ 1 ];
 };
 
 struct stored_rule
@@ -1099,11 +1327,11 @@
 
 typedef struct compiler
 {
- struct dynamic_array code[1];
- struct dynamic_array constants[1];
- struct dynamic_array labels[1];
- struct dynamic_array rules[1];
- struct dynamic_array actions[1];
+ struct dynamic_array code[ 1 ];
+ struct dynamic_array constants[ 1 ];
+ struct dynamic_array labels[ 1 ];
+ struct dynamic_array rules[ 1 ];
+ struct dynamic_array actions[ 1 ];
 } compiler;
 
 static void compiler_init( compiler * c )
@@ -1121,9 +1349,8 @@
     dynamic_array_free( c->actions );
     dynamic_array_free( c->rules );
     for ( i = 0; i < c->labels->size; ++i )
- {
- dynamic_array_free( dynamic_array_at( struct label_info, c->labels, i ).uses );
- }
+ dynamic_array_free( dynamic_array_at( struct label_info, c->labels, i
+ ).uses );
     dynamic_array_free( c->labels );
     dynamic_array_free( c->constants );
     dynamic_array_free( c->code );
@@ -1146,15 +1373,16 @@
 
 static void compile_set_label( compiler * c, int label )
 {
- struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
- int pos = c->code->size;
+ struct label_info * const l = &dynamic_array_at( struct label_info,
+ c->labels, label );
+ int const pos = c->code->size;
     int i;
     assert( l->absolute_position == -1 );
     l->absolute_position = pos;
     for ( i = 0; i < l->uses->size; ++i )
     {
         int id = dynamic_array_at( int, l->uses, i );
- int offset = (int)(pos - id - 1);
+ int offset = (int)( pos - id - 1 );
         dynamic_array_at( instruction, c->code, id ).arg = offset;
     }
 }
@@ -1169,8 +1397,9 @@
 
 static void compile_emit_branch( compiler * c, unsigned int op_code, int label )
 {
- struct label_info * l = &dynamic_array_at( struct label_info, c->labels, label );
- int pos = c->code->size;
+ struct label_info * const l = &dynamic_array_at( struct label_info,
+ c->labels, label );
+ int const pos = c->code->size;
     instruction instr;
     instr.op_code = op_code;
     if ( l->absolute_position == -1 )
@@ -1179,9 +1408,7 @@
         dynamic_array_push( l->uses, pos );
     }
     else
- {
         instr.arg = (int)( l->absolute_position - pos - 1 );
- }
     compile_emit_instruction( c, instr );
 }
 
@@ -1192,7 +1419,8 @@
     return c->constants->size - 1;
 }
 
-static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse, int num_arguments, struct arg_list * arguments, int local )
+static int compile_emit_rule( compiler * c, OBJECT * name, PARSE * parse,
+ int num_arguments, struct arg_list * arguments, int local )
 {
     struct stored_rule rule;
     rule.name = object_copy( name );
@@ -1208,7 +1436,8 @@
 {
     SUBACTION a;
     a.name = object_copy( parse->string );
- a.command = function_compile_actions( object_str( parse->string1 ), parse->file, parse->line );
+ a.command = function_compile_actions( object_str( parse->string1 ),
+ parse->file, parse->line );
     a.flags = parse->num;
     dynamic_array_push( c->actions, a );
     return (int)( c->actions->size - 1 );
@@ -1216,7 +1445,7 @@
 
 static JAM_FUNCTION * compile_to_function( compiler * c )
 {
- JAM_FUNCTION * result = BJAM_MALLOC( sizeof(JAM_FUNCTION) );
+ JAM_FUNCTION * const result = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
     int i;
     result->base.type = FUNCTION_JAM;
     result->base.reference_count = 1;
@@ -1226,27 +1455,30 @@
     result->base.rulename = 0;
 
     result->code_size = c->code->size;
- result->code = BJAM_MALLOC( c->code->size * sizeof(instruction) );
- memcpy( result->code, c->code->data, c->code->size * sizeof(instruction) );
+ result->code = BJAM_MALLOC( c->code->size * sizeof( instruction ) );
+ memcpy( result->code, c->code->data, c->code->size * sizeof( instruction ) );
 
- result->constants = BJAM_MALLOC( c->constants->size * sizeof(OBJECT *) );
- memcpy( result->constants, c->constants->data, c->constants->size * sizeof(OBJECT *) );
+ result->constants = BJAM_MALLOC( c->constants->size * sizeof( OBJECT * ) );
+ memcpy( result->constants, c->constants->data, c->constants->size * sizeof(
+ OBJECT * ) );
     result->num_constants = c->constants->size;
 
     result->num_subfunctions = c->rules->size;
- result->functions = BJAM_MALLOC( c->rules->size * sizeof(SUBFUNCTION) );
+ result->functions = BJAM_MALLOC( c->rules->size * sizeof( SUBFUNCTION ) );
     for ( i = 0; i < c->rules->size; ++i )
     {
- struct stored_rule * rule = &dynamic_array_at( struct stored_rule, c->rules, i );
- result->functions[i].name = rule->name;
- result->functions[i].code = function_compile( rule->parse );
- result->functions[i].code->num_formal_arguments = rule->num_arguments;
- result->functions[i].code->formal_arguments = rule->arguments;
- result->functions[i].local = rule->local;
+ struct stored_rule * const rule = &dynamic_array_at( struct stored_rule,
+ c->rules, i );
+ result->functions[ i ].name = rule->name;
+ result->functions[ i ].code = function_compile( rule->parse );
+ result->functions[ i ].code->num_formal_arguments = rule->num_arguments;
+ result->functions[ i ].code->formal_arguments = rule->arguments;
+ result->functions[ i ].local = rule->local;
     }
 
- result->actions = BJAM_MALLOC( c->actions->size * sizeof(SUBACTION) );
- memcpy( result->actions, c->actions->data, c->actions->size * sizeof(SUBACTION) );
+ result->actions = BJAM_MALLOC( c->actions->size * sizeof( SUBACTION ) );
+ memcpy( result->actions, c->actions->data, c->actions->size * sizeof(
+ SUBACTION ) );
     result->num_subactions = c->actions->size;
 
     result->generic = 0;
@@ -1257,18 +1489,19 @@
     return result;
 }
 
+
 /*
  * Parsing of variable expansions
  */
 
 typedef struct VAR_PARSE_GROUP
 {
- struct dynamic_array elems[1];
+ struct dynamic_array elems[ 1 ];
 } VAR_PARSE_GROUP;
 
 typedef struct VAR_PARSE_ACTIONS
 {
- struct dynamic_array elems[1];
+ struct dynamic_array elems[ 1 ];
 } VAR_PARSE_ACTIONS;
 
 #define VAR_PARSE_TYPE_VAR 0
@@ -1277,7 +1510,7 @@
 
 typedef struct _var_parse
 {
- int type; /* string or variable */
+ int type; /* string, variable or file */
 } VAR_PARSE;
 
 typedef struct
@@ -1285,7 +1518,7 @@
     VAR_PARSE base;
     VAR_PARSE_GROUP * name;
     VAR_PARSE_GROUP * subscript;
- struct dynamic_array modifiers[1];
+ struct dynamic_array modifiers[ 1 ];
 } VAR_PARSE_VAR;
 
 typedef struct
@@ -1297,19 +1530,20 @@
 typedef struct
 {
     VAR_PARSE base;
- struct dynamic_array filename[1];
- struct dynamic_array contents[1];
+ struct dynamic_array filename[ 1 ];
+ struct dynamic_array contents[ 1 ];
 } VAR_PARSE_FILE;
 
 static void var_parse_free( VAR_PARSE * );
 
+
 /*
  * VAR_PARSE_GROUP
  */
 
 static VAR_PARSE_GROUP * var_parse_group_new()
 {
- VAR_PARSE_GROUP * result = BJAM_MALLOC( sizeof( VAR_PARSE_GROUP ) );
+ VAR_PARSE_GROUP * const result = BJAM_MALLOC( sizeof( VAR_PARSE_GROUP ) );
     dynamic_array_init( result->elems );
     return result;
 }
@@ -1318,9 +1552,7 @@
 {
     int i;
     for ( i = 0; i < group->elems->size; ++i )
- {
         var_parse_free( dynamic_array_at( VAR_PARSE *, group->elems, i ) );
- }
     dynamic_array_free( group->elems );
     BJAM_FREE( group );
 }
@@ -1330,12 +1562,14 @@
     dynamic_array_push( group->elems, elem );
 }
 
-static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group, const char * start, const char * end )
+static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group,
+ char const * start, char const * end )
 {
     if ( start != end )
     {
- string buf[1];
- VAR_PARSE_STRING * value = (VAR_PARSE_STRING *)BJAM_MALLOC( sizeof(VAR_PARSE_STRING) );
+ string buf[ 1 ];
+ VAR_PARSE_STRING * const value = (VAR_PARSE_STRING *)BJAM_MALLOC(
+ sizeof(VAR_PARSE_STRING) );
         value->base.type = VAR_PARSE_TYPE_STRING;
         string_new( buf );
         string_append_range( buf, start, end );
@@ -1351,20 +1585,20 @@
     {
         VAR_PARSE * result = dynamic_array_at( VAR_PARSE *, group->elems, 0 );
         if ( result->type == VAR_PARSE_TYPE_STRING )
- {
             return (VAR_PARSE_STRING *)result;
- }
     }
     return 0;
 }
 
+
 /*
  * VAR_PARSE_ACTIONS
  */
 
 static VAR_PARSE_ACTIONS * var_parse_actions_new()
 {
- VAR_PARSE_ACTIONS * result = (VAR_PARSE_ACTIONS *)BJAM_MALLOC( sizeof(VAR_PARSE_ACTIONS) );
+ VAR_PARSE_ACTIONS * const result = (VAR_PARSE_ACTIONS *)BJAM_MALLOC(
+ sizeof(VAR_PARSE_ACTIONS) );
     dynamic_array_init( result->elems );
     return result;
 }
@@ -1373,13 +1607,13 @@
 {
     int i;
     for ( i = 0; i < actions->elems->size; ++i )
- {
- var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, actions->elems, i ) );
- }
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
+ actions->elems, i ) );
     dynamic_array_free( actions->elems );
     BJAM_FREE( actions );
 }
 
+
 /*
  * VAR_PARSE_VAR
  */
@@ -1400,8 +1634,9 @@
     var_parse_group_free( var->name );
     if ( var->subscript )
         var_parse_group_free( var->subscript );
- for( i = 0; i < var->modifiers->size; ++i )
- var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, var->modifiers, i ) );
+ for ( i = 0; i < var->modifiers->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
+ var->modifiers, i ) );
     dynamic_array_free( var->modifiers );
     BJAM_FREE( var );
 }
@@ -1413,6 +1648,7 @@
     return result;
 }
 
+
 /*
  * VAR_PARSE_STRING
  */
@@ -1423,13 +1659,15 @@
     BJAM_FREE( string );
 }
 
+
 /*
  * VAR_PARSE_FILE
  */
 
 static VAR_PARSE_FILE * var_parse_file_new( void )
 {
- VAR_PARSE_FILE * result = (VAR_PARSE_FILE *)BJAM_MALLOC( sizeof( VAR_PARSE_FILE ) );
+ VAR_PARSE_FILE * const result = (VAR_PARSE_FILE *)BJAM_MALLOC( sizeof(
+ VAR_PARSE_FILE ) );
     result->base.type = VAR_PARSE_TYPE_FILE;
     dynamic_array_init( result->filename );
     dynamic_array_init( result->contents );
@@ -1439,83 +1677,102 @@
 static void var_parse_file_free( VAR_PARSE_FILE * file )
 {
     int i;
- for( i = 0; i < file->filename->size; ++i )
- var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, file->filename, i ) );
+ for ( i = 0; i < file->filename->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
+ file->filename, i ) );
     dynamic_array_free( file->filename );
- for( i = 0; i < file->contents->size; ++i )
- var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *, file->contents, i ) );
+ for ( i = 0; i < file->contents->size; ++i )
+ var_parse_group_free( dynamic_array_at( VAR_PARSE_GROUP *,
+ file->contents, i ) );
     dynamic_array_free( file->contents );
     BJAM_FREE( file );
 }
 
+
 /*
  * VAR_PARSE
  */
 
 static void var_parse_free( VAR_PARSE * parse )
 {
- if ( parse->type == VAR_PARSE_TYPE_VAR )
- {
- var_parse_var_free( (VAR_PARSE_VAR *)parse );
- }
- else if ( parse->type == VAR_PARSE_TYPE_STRING )
- {
- var_parse_string_free( (VAR_PARSE_STRING *)parse );
- }
- else if ( parse->type == VAR_PARSE_TYPE_FILE )
- {
- var_parse_file_free( (VAR_PARSE_FILE *)parse );
- }
- else
+ switch ( parse->type )
     {
- assert(!"Invalid type");
+ case VAR_PARSE_TYPE_VAR:
+ var_parse_var_free( (VAR_PARSE_VAR *)parse );
+ break;
+
+ case VAR_PARSE_TYPE_STRING:
+ var_parse_string_free( (VAR_PARSE_STRING *)parse );
+ break;
+
+ case VAR_PARSE_TYPE_FILE:
+ var_parse_file_free( (VAR_PARSE_FILE *)parse );
+ break;
+
+ default:
+ assert( !"Invalid type" );
     }
 }
 
+
 /*
  * Compile VAR_PARSE
  */
 
-static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c );
+static void var_parse_group_compile( VAR_PARSE_GROUP const * parse,
+ compiler * c );
 
-static void var_parse_var_compile( const VAR_PARSE_VAR * parse, compiler * c )
+static void var_parse_var_compile( VAR_PARSE_VAR const * parse, compiler * c )
 {
     int expand_name = 0;
+ int is_get_grist = 0;
+ int has_modifiers = 0;
+ /* Special case common modifiers */
+ if ( parse->modifiers->size == 1 )
+ {
+ VAR_PARSE_GROUP * mod = dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, 0 );
+ if ( mod->elems->size == 1 )
+ {
+ VAR_PARSE * mod1 = dynamic_array_at( VAR_PARSE *, mod->elems, 0 );
+ if ( mod1->type == VAR_PARSE_TYPE_STRING )
+ {
+ OBJECT * s = ( (VAR_PARSE_STRING *)mod1 )->s;
+ if ( ! strcmp ( object_str( s ), "G" ) )
+ {
+ is_get_grist = 1;
+ }
+ }
+ }
+ }
     /* If there are modifiers, emit them in reverse order. */
- if ( parse->modifiers->size > 0 )
+ if ( parse->modifiers->size > 0 && !is_get_grist )
     {
         int i;
+ has_modifiers = 1;
         for ( i = 0; i < parse->modifiers->size; ++i )
- {
- var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->modifiers, parse->modifiers->size - i - 1 ), c );
- }
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
+ parse->modifiers, parse->modifiers->size - i - 1 ), c );
     }
 
- /* If there's a subscript, emit it. */
+ /* If there is a subscript, emit it. */
     if ( parse->subscript )
- {
         var_parse_group_compile( parse->subscript, c );
- }
 
     /* If the variable name is empty, look it up. */
     if ( parse->name->elems->size == 0 )
- {
- compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, constant_empty ) );
- }
- /* If the variable name doesn't need to be expanded, look it up. */
- else if ( parse->name->elems->size == 1 &&
- dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
- {
- OBJECT * name = ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, parse->name->elems, 0 ) )->s;
- int idx = get_argument_index( object_str( name ) );
+ compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c,
+ constant_empty ) );
+ /* If the variable name does not need to be expanded, look it up. */
+ else if ( parse->name->elems->size == 1 && dynamic_array_at( VAR_PARSE *,
+ parse->name->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ {
+ OBJECT * const name = ( (VAR_PARSE_STRING *)dynamic_array_at(
+ VAR_PARSE *, parse->name->elems, 0 ) )->s;
+ int const idx = get_argument_index( object_str( name ) );
         if ( idx != -1 )
- {
             compile_emit( c, INSTR_PUSH_ARG, idx );
- }
         else
- {
             compile_emit( c, INSTR_PUSH_VAR, compile_emit_constant( c, name ) );
- }
     }
     /* Otherwise, push the var names and use the group instruction. */
     else
@@ -1525,164 +1782,156 @@
     }
 
     /** Select the instruction for expanding the variable. */
- if ( !parse->modifiers->size && !parse->subscript && !expand_name )
- {
- /* Nothing to do */
- }
- else if ( !parse->modifiers->size && !parse->subscript && expand_name )
- {
+ if ( !has_modifiers && !parse->subscript && !expand_name )
+ ;
+ else if ( !has_modifiers && !parse->subscript && expand_name )
         compile_emit( c, INSTR_PUSH_GROUP, 0 );
- }
- else if ( !parse->modifiers->size && parse->subscript && !expand_name )
- {
+ else if ( !has_modifiers && parse->subscript && !expand_name )
         compile_emit( c, INSTR_APPLY_INDEX, 0 );
- }
- else if ( !parse->modifiers->size && parse->subscript && expand_name )
- {
+ else if ( !has_modifiers && parse->subscript && expand_name )
         compile_emit( c, INSTR_APPLY_INDEX_GROUP, 0 );
- }
- if ( parse->modifiers->size && !parse->subscript && !expand_name )
- {
+ else if ( has_modifiers && !parse->subscript && !expand_name )
         compile_emit( c, INSTR_APPLY_MODIFIERS, parse->modifiers->size );
- }
- else if ( parse->modifiers->size && !parse->subscript && expand_name )
- {
+ else if ( has_modifiers && !parse->subscript && expand_name )
         compile_emit( c, INSTR_APPLY_MODIFIERS_GROUP, parse->modifiers->size );
- }
- else if ( parse->modifiers->size && parse->subscript && !expand_name )
- {
+ else if ( has_modifiers && parse->subscript && !expand_name )
         compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS, parse->modifiers->size );
- }
- else if ( parse->modifiers->size && parse->subscript && expand_name )
+ else if ( has_modifiers && parse->subscript && expand_name )
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP,
+ parse->modifiers->size );
+
+ /* Now apply any special modifiers */
+ if ( is_get_grist )
     {
- compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP, parse->modifiers->size );
+ compile_emit( c, INSTR_GET_GRIST, 0 );
     }
 }
 
-static void var_parse_string_compile( const VAR_PARSE_STRING * parse, compiler * c )
+static void var_parse_string_compile( VAR_PARSE_STRING const * parse,
+ compiler * c )
 {
- compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, parse->s ) );
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, parse->s )
+ );
 }
 
-static void var_parse_file_compile( const VAR_PARSE_FILE * parse, compiler * c )
+static void var_parse_file_compile( VAR_PARSE_FILE const * parse, compiler * c )
 {
     int i;
     for ( i = 0; i < parse->filename->size; ++i )
- {
- var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->filename, parse->filename->size - i - 1 ), c );
- }
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
+ parse->filename, parse->filename->size - i - 1 ), c );
     compile_emit( c, INSTR_APPEND_STRINGS, parse->filename->size );
     for ( i = 0; i < parse->contents->size; ++i )
- {
- var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, parse->contents, parse->contents->size - i - 1 ), c );
- }
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
+ parse->contents, parse->contents->size - i - 1 ), c );
     compile_emit( c, INSTR_WRITE_FILE, parse->contents->size );
 }
 
-static void var_parse_compile( const VAR_PARSE * parse, compiler * c )
+static void var_parse_compile( VAR_PARSE const * parse, compiler * c )
 {
- if( parse->type == VAR_PARSE_TYPE_VAR )
- {
- var_parse_var_compile( (const VAR_PARSE_VAR *)parse, c );
- }
- else if( parse->type == VAR_PARSE_TYPE_STRING )
- {
- var_parse_string_compile( (const VAR_PARSE_STRING *)parse, c );
- }
- else if( parse->type == VAR_PARSE_TYPE_FILE )
- {
- var_parse_file_compile( (const VAR_PARSE_FILE *)parse, c );
- }
- else
+ switch ( parse->type )
     {
- assert( !"Unknown var parse type." );
+ case VAR_PARSE_TYPE_VAR:
+ var_parse_var_compile( (VAR_PARSE_VAR const *)parse, c );
+ break;
+
+ case VAR_PARSE_TYPE_STRING:
+ var_parse_string_compile( (VAR_PARSE_STRING const *)parse, c );
+ break;
+
+ case VAR_PARSE_TYPE_FILE:
+ var_parse_file_compile( (VAR_PARSE_FILE const *)parse, c );
+ break;
+
+ default:
+ assert( !"Unknown var parse type." );
     }
 }
 
-static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c )
+static void var_parse_group_compile( VAR_PARSE_GROUP const * parse, compiler * c
+ )
 {
     /* Emit the elements in reverse order. */
     int i;
- for( i = 0; i < parse->elems->size; ++i)
- {
- var_parse_compile( dynamic_array_at( VAR_PARSE *, parse->elems, parse->elems->size - i - 1 ), c );
- }
- /* If there're no elements, emit an empty string. */
+ for ( i = 0; i < parse->elems->size; ++i )
+ var_parse_compile( dynamic_array_at( VAR_PARSE *, parse->elems,
+ parse->elems->size - i - 1 ), c );
+ /* If there are no elements, emit an empty string. */
     if ( parse->elems->size == 0 )
- {
- compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_empty ) );
- }
- /* If there's more than one element, combine them. */
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c,
+ constant_empty ) );
+ /* If there is more than one element, combine them. */
     if ( parse->elems->size > 1 )
- {
         compile_emit( c, INSTR_COMBINE_STRINGS, parse->elems->size );
- }
 }
 
-static void var_parse_actions_compile( const VAR_PARSE_ACTIONS * actions, compiler * c )
+static void var_parse_actions_compile( VAR_PARSE_ACTIONS const * actions,
+ compiler * c )
 {
     int i;
     for ( i = 0; i < actions->elems->size; ++i )
- {
- var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *, actions->elems, actions->elems->size - i - 1 ), c );
- }
+ var_parse_group_compile( dynamic_array_at( VAR_PARSE_GROUP *,
+ actions->elems, actions->elems->size - i - 1 ), c );
     compile_emit( c, INSTR_OUTPUT_STRINGS, actions->elems->size );
 }
 
+
 /*
  * Parse VAR_PARSE_VAR
  */
 
-static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end );
-static VAR_PARSE * parse_variable( const char * * string );
-static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
-static void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out);
-static void parse_var_string( const char * first, const char * last, struct dynamic_array * out );
+static VAR_PARSE * parse_at_file( char const * start, char const * mid,
+ char const * end );
+static VAR_PARSE * parse_variable( char const * * string );
+static int try_parse_variable( char const * * s_, char const * * string,
+ VAR_PARSE_GROUP * out );
+static void balance_parentheses( char const * * s_, char const * * string,
+ VAR_PARSE_GROUP * out );
+static void parse_var_string( char const * first, char const * last,
+ struct dynamic_array * out );
+
 
 /*
  * Parses a string that can contain variables to expand.
  */
 
-static VAR_PARSE_GROUP * parse_expansion( const char * * string )
+static VAR_PARSE_GROUP * parse_expansion( char const * * string )
 {
     VAR_PARSE_GROUP * result = var_parse_group_new();
- const char * s = *string;
- for (;;)
+ char const * s = *string;
+ for ( ; ; )
     {
- if(try_parse_variable( &s, string, result )) {}
- else if(s[0] == '\0')
+ if ( try_parse_variable( &s, string, result ) ) {}
+ else if ( s[ 0 ] == '\0' )
         {
             var_parse_group_maybe_add_constant( result, *string, s );
             return result;
         }
         else
- {
             ++s;
- }
     }
 }
 
-static VAR_PARSE_ACTIONS * parse_actions( const char * string )
+static VAR_PARSE_ACTIONS * parse_actions( char const * string )
 {
- VAR_PARSE_ACTIONS * result = var_parse_actions_new();
+ VAR_PARSE_ACTIONS * const result = var_parse_actions_new();
     parse_var_string( string, string + strlen( string ), result->elems );
     return result;
 }
 
 /*
- * Checks whether the string a *s_ starts with
- * a variable expansion "$(". *string should point
- * to the first unemitted character before *s.
- * If *s_ starts with variable expansion, appends
- * elements to out up to the closing ")", and
- * adjusts *s_ and *string to point to next character.
- * Returns 1 if s_ starts with a variable, 0 otherwise.
+ * Checks whether the string a *s_ starts with a variable expansion "$(".
+ * *string should point to the first unemitted character before *s. If *s_
+ * starts with variable expansion, appends elements to out up to the closing
+ * ")", and adjusts *s_ and *string to point to next character. Returns 1 if s_
+ * starts with a variable, 0 otherwise.
  */
 
-static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+static int try_parse_variable( char const * * s_, char const * * string,
+ VAR_PARSE_GROUP * out )
 {
- const char * s = *s_;
- if(s[0] == '$' && s[1] == '(')
+ char const * s = *s_;
+ if ( s[ 0 ] == '$' && s[ 1 ] == '(' )
     {
         var_parse_group_maybe_add_constant( out, *string, s );
         s += 2;
@@ -1691,11 +1940,11 @@
         *s_ = s;
         return 1;
     }
- else if(s[0] == '@' && s[1] == '(')
+ if ( s[ 0 ] == '@' && s[ 1 ] == '(' )
     {
         int depth = 1;
- const char * ine;
- const char * split = 0;
+ char const * ine;
+ char const * split = 0;
         var_parse_group_maybe_add_constant( out, *string, s );
         s += 2;
         ine = s;
@@ -1708,54 +1957,50 @@
             case '(': ++depth; break;
             case ')': --depth; break;
             case ':':
- if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
+ if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '='
+ ) )
                     split = ine;
                 break;
             }
             ++ine;
         }
-
- if ( !split || depth != 0 )
- {
+
+ if ( !split || depth )
             return 0;
- }
-
+
         var_parse_group_add( out, parse_at_file( s, split, ine - 1 ) );
         *string = ine;
         *s_ = ine;
-
         return 1;
     }
- else
- {
- return 0;
- }
+ return 0;
 }
 
-static const char * current_file = "";
+
+static char const * current_file = "";
 static int current_line;
 
-static void parse_error( const char * message )
+static void parse_error( char const * message )
 {
     printf( "%s:%d: %s\n", current_file, current_line, message );
 }
 
+
 /*
- * Parses a single variable up to the closing ")" and
- * adjusts *string to point to the next character. *string
- * should point to the character immediately after
- * the initial "$("
+ * Parses a single variable up to the closing ")" and adjusts *string to point
+ * to the next character. *string should point to the character immediately
+ * after the initial "$(".
  */
 
-static VAR_PARSE * parse_variable( const char * * string )
+static VAR_PARSE * parse_variable( char const * * string )
 {
- VAR_PARSE_VAR * result = var_parse_var_new();
- VAR_PARSE_GROUP * name = result->name;
- const char * s = *string;
+ VAR_PARSE_VAR * const result = var_parse_var_new();
+ VAR_PARSE_GROUP * const name = result->name;
+ char const * s = *string;
     for ( ; ; )
     {
         if ( try_parse_variable( &s, string, name ) ) {}
- else if ( s[0] == ':' )
+ else if ( s[ 0 ] == ':' )
         {
             VAR_PARSE_GROUP * mod;
             var_parse_group_maybe_add_constant( name, *string, s );
@@ -1765,31 +2010,29 @@
             for ( ; ; )
             {
                 if ( try_parse_variable( &s, string, mod ) ) {}
- else if ( s[0] == ')' )
+ else if ( s[ 0 ] == ')' )
                 {
                     var_parse_group_maybe_add_constant( mod, *string, s );
- ++s;
- *string = s;
+ *string = ++s;
                     return (VAR_PARSE *)result;
                 }
- else if ( s[0] == '(' )
+ else if ( s[ 0 ] == '(' )
                 {
                     ++s;
                     balance_parentheses( &s, string, mod );
                 }
- else if ( s[0] == ':' )
+ else if ( s[ 0 ] == ':' )
                 {
                     var_parse_group_maybe_add_constant( mod, *string, s );
- ++s;
- *string = s;
+ *string = ++s;
                     mod = var_parse_var_new_modifier( result );
                 }
- else if ( s[0] == '[' )
+ else if ( s[ 0 ] == '[' )
                 {
                     parse_error("unexpected subscript");
                     ++s;
                 }
- else if ( s[0] == '\0' )
+ else if ( s[ 0 ] == '\0' )
                 {
                     parse_error( "unbalanced parentheses" );
                     var_parse_group_maybe_add_constant( mod, *string, s );
@@ -1797,41 +2040,31 @@
                     return (VAR_PARSE *)result;
                 }
                 else
- {
                     ++s;
- }
             }
         }
- else if ( s[0] == '[' )
+ else if ( s[ 0 ] == '[' )
         {
             VAR_PARSE_GROUP * subscript = var_parse_group_new();
             result->subscript = subscript;
             var_parse_group_maybe_add_constant( name, *string, s );
- ++s;
- *string = s;
+ *string = ++s;
             for ( ; ; )
             {
                 if ( try_parse_variable( &s, string, subscript ) ) {}
- else if ( s[0] == ']' )
+ else if ( s[ 0 ] == ']' )
                 {
                     var_parse_group_maybe_add_constant( subscript, *string, s );
- ++s;
- *string = s;
- if ( s[0] == ')' || s[0] == ':' || s[0] == '\0')
- {
- break;
- }
- else
- {
+ *string = ++s;
+ if ( s[ 0 ] != ')' && s[ 0 ] != ':' && s[ 0 ] != '\0' )
                         parse_error( "unexpected text following []" );
- break;
- }
+ break;
                 }
- else if ( isdigit( s[0] ) || s[0] == '-' )
+ else if ( isdigit( s[ 0 ] ) || s[ 0 ] == '-' )
                 {
                     ++s;
                 }
- else if( s[0] == '\0' )
+ else if ( s[ 0 ] == '\0' )
                 {
                     parse_error( "malformed subscript" );
                     break;
@@ -1843,19 +2076,18 @@
                 }
             }
         }
- else if ( s[0] == ')' )
+ else if ( s[ 0 ] == ')' )
         {
             var_parse_group_maybe_add_constant( name, *string, s );
- ++s;
- *string = s;
+ *string = ++s;
             return (VAR_PARSE *)result;
         }
- else if ( s[0] == '(' )
+ else if ( s[ 0 ] == '(' )
         {
             ++s;
             balance_parentheses( &s, string, name );
         }
- else if ( s[0] == '\0' )
+ else if ( s[ 0 ] == '\0' )
         {
             parse_error( "unbalanced parentheses" );
             var_parse_group_maybe_add_constant( name, *string, s );
@@ -1863,64 +2095,55 @@
             return (VAR_PARSE *)result;
         }
         else
- {
             ++s;
- }
     }
 }
 
-static void parse_var_string( const char * first, const char * last, struct dynamic_array * out )
+static void parse_var_string( char const * first, char const * last,
+ struct dynamic_array * out )
 {
- const char * saved = first;
- for ( ; ; )
+ char const * saved = first;
+ while ( first != last )
     {
- /* Handle whitespace */
- for ( ; first != last; ++first ) if ( !isspace(*first) ) break;
+ /* Handle whitespace. */
+ while ( first != last && isspace( *first ) ) ++first;
         if ( saved != first )
         {
- VAR_PARSE_GROUP * group = var_parse_group_new();
+ VAR_PARSE_GROUP * const group = var_parse_group_new();
             var_parse_group_maybe_add_constant( group, saved, first );
             saved = first;
             dynamic_array_push( out, group );
         }
-
         if ( first == last ) break;
 
         /* Handle non-whitespace */
-
         {
             VAR_PARSE_GROUP * group = var_parse_group_new();
             for ( ; ; )
             {
-
- if( first == last || isspace( *first ) )
+ if ( first == last || isspace( *first ) )
                 {
                     var_parse_group_maybe_add_constant( group, saved, first );
                     saved = first;
                     break;
                 }
- else if ( try_parse_variable( &first, &saved, group ) )
- {
+ if ( try_parse_variable( &first, &saved, group ) )
                     assert( first <= last );
- }
- else
- {
+ else
                     ++first;
- }
             }
             dynamic_array_push( out, group );
         }
- if ( first == last ) break;
     }
 }
 
 /*
- * start should point to the character immediately following the
- * opening "@(", mid should point to the ":E=", and end should
- * point to the closing ")".
+ * start should point to the character immediately following the opening "@(",
+ * mid should point to the ":E=", and end should point to the closing ")".
  */
 
-static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end )
+static VAR_PARSE * parse_at_file( char const * start, char const * mid,
+ char const * end )
 {
     VAR_PARSE_FILE * result = var_parse_file_new();
     parse_var_string( start, mid, result->filename );
@@ -1929,54 +2152,51 @@
 }
 
 /*
- * Given that *s_ points to the character after a "(",
- * parses up to the matching ")". *string should
- * point to the first unemitted character before *s_.
+ * Given that *s_ points to the character after a "(", parses up to the matching
+ * ")". *string should point to the first unemitted character before *s_.
  *
- * When the function returns, *s_ will point to the character
- * after the ")", and *string will point to the first
- * unemitted character before *s_. The range from *string
- * to *s_ does not contain any variables that need to be
- * expanded.
+ * When the function returns, *s_ will point to the character after the ")", and
+ * *string will point to the first unemitted character before *s_. The range
+ * from *string to *s_ does not contain any variables that need to be expanded.
  */
 
-void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+void balance_parentheses( char const * * s_, char const * * string,
+ VAR_PARSE_GROUP * out)
 {
     int depth = 1;
- const char * s = *s_;
+ char const * s = *s_;
     for ( ; ; )
     {
         if ( try_parse_variable( &s, string, out ) ) { }
- else if(s[0] == ':' || s[0] == '[')
+ else if ( s[ 0 ] == ':' || s[ 0 ] == '[' )
         {
             parse_error( "unbalanced parentheses" );
             ++s;
         }
- else if(s[0] == '\0')
+ else if ( s[ 0 ] == '\0' )
         {
             parse_error( "unbalanced parentheses" );
             break;
         }
- else if(s[0] == ')')
+ else if ( s[ 0 ] == ')' )
         {
             ++s;
- if(--depth == 0) break;
+ if ( --depth == 0 ) break;
         }
- else if(s[0] == '(')
+ else if ( s[ 0 ] == '(' )
         {
             ++depth;
             ++s;
         }
         else
- {
             ++s;
- }
     }
     *s_ = s;
 }
 
+
 /*
- * Main compile
+ * Main compile.
  */
 
 #define RESULT_STACK 0
@@ -1991,17 +2211,15 @@
     assert( parse->type == PARSE_EVAL );
     switch ( parse->num )
     {
- case EXPR_EXISTS:
- {
+ case EXPR_EXISTS:
             compile_parse( parse->left, c, RESULT_STACK );
             if ( branch_true )
                 compile_emit_branch( c, INSTR_JUMP_NOT_EMPTY, label );
             else
                 compile_emit_branch( c, INSTR_JUMP_EMPTY, label );
             break;
- }
- case EXPR_EQUALS:
- {
+
+ case EXPR_EQUALS:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2009,9 +2227,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_NE, label );
             break;
- }
- case EXPR_NOTEQ:
- {
+
+ case EXPR_NOTEQ:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2019,9 +2236,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_EQ, label );
             break;
- }
- case EXPR_LESS:
- {
+
+ case EXPR_LESS:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2029,9 +2245,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_GE, label );
             break;
- }
- case EXPR_LESSEQ:
- {
+
+ case EXPR_LESSEQ:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2039,9 +2254,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_GT, label );
             break;
- }
- case EXPR_MORE:
- {
+
+ case EXPR_MORE:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2049,9 +2263,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_LE, label );
             break;
- }
- case EXPR_MOREEQ:
- {
+
+ case EXPR_MOREEQ:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2059,9 +2272,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_LT, label );
             break;
- }
- case EXPR_IN:
- {
+
+ case EXPR_IN:
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
             if ( branch_true )
@@ -2069,9 +2281,8 @@
             else
                 compile_emit_branch( c, INSTR_JUMP_NOT_IN, label );
             break;
- }
- case EXPR_AND:
- {
+
+ case EXPR_AND:
             if ( branch_true )
             {
                 int f = compile_new_label( c );
@@ -2085,9 +2296,8 @@
                 compile_condition( parse->right, c, 0, label );
             }
             break;
- }
- case EXPR_OR:
- {
+
+ case EXPR_OR:
             if ( branch_true )
             {
                 compile_condition( parse->left, c, 1, label );
@@ -2101,24 +2311,23 @@
                 compile_set_label( c, t );
             }
             break;
- }
- case EXPR_NOT:
- {
+
+ case EXPR_NOT:
             compile_condition( parse->left, c, !branch_true, label );
             break;
- }
     }
 }
 
-static void adjust_result( compiler * c, int actual_location, int desired_location )
+static void adjust_result( compiler * c, int actual_location,
+ int desired_location )
 {
     if ( actual_location == desired_location )
         ;
     else if ( actual_location == RESULT_STACK && desired_location == RESULT_RETURN )
         compile_emit( c, INSTR_SET_RESULT, 0 );
- else if( actual_location == RESULT_STACK && desired_location == RESULT_NONE )
+ else if ( actual_location == RESULT_STACK && desired_location == RESULT_NONE )
         compile_emit( c, INSTR_POP, 0 );
- else if( actual_location == RESULT_RETURN && desired_location == RESULT_STACK )
+ else if ( actual_location == RESULT_RETURN && desired_location == RESULT_STACK )
         compile_emit( c, INSTR_PUSH_RESULT, 0 );
     else if ( actual_location == RESULT_RETURN && desired_location == RESULT_NONE )
         ;
@@ -2130,12 +2339,10 @@
         compile_emit( c, INSTR_SET_RESULT, 0 );
     }
     else
- {
         assert( !"invalid result location" );
- }
 }
 
-static const char * parse_type( PARSE * parse )
+static char const * parse_type( PARSE * parse )
 {
     switch ( parse->type )
     {
@@ -2150,9 +2357,7 @@
 {
     assert( parse->type == PARSE_APPEND );
     if ( parse->left->type == PARSE_NULL )
- {
         compile_parse( parse->right, c, RESULT_STACK );
- }
     else
     {
         if ( parse->left->type == PARSE_APPEND )
@@ -2173,21 +2378,23 @@
     }
     else if ( parse->type == PARSE_EVAL )
     {
- /* FIXME: This is only needed because of the bizarre parsing of conditions. */
+ /* FIXME: This is only needed because of the bizarre parsing of
+ * conditions.
+ */
         if ( parse->num == EXPR_EXISTS )
- {
             compile_parse( parse->left, c, result_location );
- }
         else
         {
             int f = compile_new_label( c );
             int end = compile_new_label( c );
 
- printf( "%s:%d: Conditional used as list (check operator precedence).\n", object_str(parse->file), parse->line );
-
+ printf( "%s:%d: Conditional used as list (check operator "
+ "precedence).\n", object_str( parse->file ), parse->line );
+
             /* Emit the condition */
             compile_condition( parse, c, 0, f );
- compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c, constant_true ) );
+ compile_emit( c, INSTR_PUSH_CONSTANT, compile_emit_constant( c,
+ constant_true ) );
             compile_emit_branch( c, INSTR_JUMP, end );
             compile_set_label( c, f );
             compile_emit( c, INSTR_PUSH_EMPTY, 0 );
@@ -2218,7 +2425,6 @@
         compile_set_label( c, top );
         compile_emit_branch( c, INSTR_FOR_LOOP, end );
         compile_emit( c, INSTR_SET, var );
- compile_emit( c, INSTR_POP, 0 );
 
         /* Run the loop body */
         compile_parse( parse->right, c, RESULT_NONE );
@@ -2227,13 +2433,11 @@
         compile_set_label( c, end );
 
         if ( parse->num )
- {
             compile_emit( c, INSTR_POP_LOCAL, var );
- }
 
         adjust_result( c, RESULT_NONE, result_location);
     }
- else if( parse->type == PARSE_IF )
+ else if ( parse->type == PARSE_IF )
     {
         int f = compile_new_label( c );
         /* Emit the condition */
@@ -2250,24 +2454,25 @@
             compile_set_label( c, end );
         }
         else
- {
             compile_set_label( c, f );
- }
 
     }
- else if( parse->type == PARSE_WHILE )
+ else if ( parse->type == PARSE_WHILE )
     {
- int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ int nested_result = result_location == RESULT_NONE
+ ? RESULT_NONE
+ : RESULT_RETURN;
         int test = compile_new_label( c );
         int top = compile_new_label( c );
- /* Make sure that we return an empty list if the loop runs zero times. */
+ /* Make sure that we return an empty list if the loop runs zero times.
+ */
         adjust_result( c, RESULT_NONE, nested_result );
- /* Jump to the loop test */
+ /* Jump to the loop test. */
         compile_emit_branch( c, INSTR_JUMP, test );
         compile_set_label( c, top );
- /* Emit the loop body */
+ /* Emit the loop body. */
         compile_parse( parse->right, c, nested_result );
- /* Emit the condition */
+ /* Emit the condition. */
         compile_set_label( c, test );
         compile_condition( parse->left, c, 1, top );
 
@@ -2282,7 +2487,9 @@
     }
     else if ( parse->type == PARSE_MODULE )
     {
- int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
+ int const nested_result = result_location == RESULT_NONE
+ ? RESULT_NONE
+ : RESULT_RETURN;
         compile_parse( parse->left, c, RESULT_STACK );
         compile_emit( c, INSTR_PUSH_MODULE, 0 );
         compile_parse( parse->right, c, nested_result );
@@ -2295,13 +2502,9 @@
         compile_parse( parse->left->right, c, RESULT_STACK );
         /* Evaluate the base classes. */
         if ( parse->left->left )
- {
             compile_parse( parse->left->left->right, c, RESULT_STACK );
- }
         else
- {
             compile_emit( c, INSTR_PUSH_EMPTY, 0 );
- }
         compile_emit( c, INSTR_CLASS, 0 );
         compile_parse( parse->right, c, RESULT_NONE );
         compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
@@ -2311,8 +2514,8 @@
     }
     else if ( parse->type == PARSE_LIST )
     {
- OBJECT * o = parse->string;
- const char * s = object_str( o );
+ OBJECT * const o = parse->string;
+ char const * s = object_str( o );
         VAR_PARSE_GROUP * group;
         current_file = object_str( parse->file );
         current_line = parse->line;
@@ -2323,10 +2526,10 @@
     }
     else if ( parse->type == PARSE_LOCAL )
     {
- int nested_result = result_location == RESULT_NONE? RESULT_NONE : RESULT_RETURN;
- /*
- * This should be left recursive group of compile_appends
- */
+ int nested_result = result_location == RESULT_NONE
+ ? RESULT_NONE
+ : RESULT_RETURN;
+ /* This should be left recursive group of compile_appends. */
         PARSE * vars = parse->left;
 
         /* Special case an empty list of vars */
@@ -2336,22 +2539,21 @@
             compile_parse( parse->third, c, result_location );
             nested_result = result_location;
         }
- /*
- * Check whether there is exactly one variable
- * with a constant name
- */
+ /* Check whether there is exactly one variable with a constant name. */
         else if ( vars->left->type == PARSE_NULL &&
             vars->right->type == PARSE_LIST )
         {
- const char * s = object_str( vars->right->string );
+ char const * s = object_str( vars->right->string );
             VAR_PARSE_GROUP * group;
             current_file = object_str( parse->file );
             current_line = parse->line;
             group = parse_expansion( &s );
- if ( group->elems->size == 1 &&
- dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ if ( group->elems->size == 1 && dynamic_array_at( VAR_PARSE *,
+ group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
             {
- int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ int const name = compile_emit_constant( c, (
+ (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *,
+ group->elems, 0 ) )->s );
                 var_parse_group_free( group );
                 compile_parse( parse->right, c, RESULT_STACK );
                 compile_emit( c, INSTR_PUSH_LOCAL, name );
@@ -2380,12 +2582,62 @@
     }
     else if ( parse->type == PARSE_ON )
     {
- int end = compile_new_label( c );
- compile_parse( parse->left, c, RESULT_STACK );
- compile_emit_branch( c, INSTR_PUSH_ON, end );
- compile_parse( parse->right, c, RESULT_STACK );
- compile_emit( c, INSTR_POP_ON, 0 );
- compile_set_label( c, end );
+ if ( parse->right->type == PARSE_APPEND &&
+ parse->right->left->type == PARSE_NULL &&
+ parse->right->right->type == PARSE_LIST )
+ {
+ /* [ on $(target) return $(variable) ] */
+ PARSE * value = parse->right->right;
+ OBJECT * const o = value->string;
+ char const * s = object_str( o );
+ VAR_PARSE_GROUP * group;
+ OBJECT * varname = 0;
+ current_file = object_str( value->file );
+ current_line = value->line;
+ group = parse_expansion( &s );
+ if ( group->elems->size == 1 )
+ {
+ VAR_PARSE * one = dynamic_array_at( VAR_PARSE *, group->elems, 0 );
+ if ( one->type == VAR_PARSE_TYPE_VAR )
+ {
+ VAR_PARSE_VAR * var = ( VAR_PARSE_VAR * )one;
+ if ( var->modifiers->size == 0 && !var->subscript && var->name->elems->size == 1 )
+ {
+ VAR_PARSE * name = dynamic_array_at( VAR_PARSE *, var->name->elems, 0 );
+ if ( name->type == VAR_PARSE_TYPE_STRING )
+ {
+ varname = ( ( VAR_PARSE_STRING * )name )->s;
+ }
+ }
+ }
+ }
+ if ( varname )
+ {
+ /* We have one variable with a fixed name and no modifiers. */
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_GET_ON, compile_emit_constant( c, varname ) );
+ }
+ else
+ {
+ /* Too complex. Fall back on push/pop. */
+ int end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit_branch( c, INSTR_PUSH_ON, end );
+ var_parse_group_compile( group, c );
+ compile_emit( c, INSTR_POP_ON, 0 );
+ compile_set_label( c, end );
+ }
+ var_parse_group_free( group );
+ }
+ else
+ {
+ int end = compile_new_label( c );
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit_branch( c, INSTR_PUSH_ON, end );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_POP_ON, 0 );
+ compile_set_label( c, end );
+ }
         adjust_result( c, RESULT_STACK, result_location );
     }
     else if ( parse->type == PARSE_RULE )
@@ -2393,24 +2645,41 @@
         PARSE * p;
         int n = 0;
         VAR_PARSE_GROUP * group;
- const char * s = object_str( parse->string );
+ char const * s = object_str( parse->string );
 
- if ( parse->left->left == NULL && parse->left->right->type == PARSE_NULL )
- ;
- else
+ if ( parse->left->left || parse->left->right->type != PARSE_NULL )
             for ( p = parse->left; p; p = p->left )
             {
                 compile_parse( p->right, c, RESULT_STACK );
                 ++n;
             }
-
+
         current_file = object_str( parse->file );
         current_line = parse->line;
         group = parse_expansion( &s );
- var_parse_group_compile( group, c );
- var_parse_group_free( group );
- compile_emit( c, INSTR_CALL_RULE, n );
- compile_emit( c, compile_emit_constant( c, parse->string ), parse->line );
+
+ if ( group->elems->size == 2 &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_VAR &&
+ dynamic_array_at( VAR_PARSE *, group->elems, 1 )->type == VAR_PARSE_TYPE_STRING &&
+ ( object_str( ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 1 ) )->s )[ 0 ] == '.' ) )
+ {
+ VAR_PARSE_STRING * access = (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 1 );
+ OBJECT * member = object_new( object_str( access->s ) + 1 );
+ /* Emit the object */
+ var_parse_var_compile( (VAR_PARSE_VAR *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ), c );
+ var_parse_group_free( group );
+ compile_emit( c, INSTR_CALL_MEMBER_RULE, n );
+ compile_emit( c, compile_emit_constant( c, member ), parse->line );
+ object_free( member );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_emit( c, INSTR_CALL_RULE, n );
+ compile_emit( c, compile_emit_constant( c, parse->string ), parse->line );
+ }
+
         adjust_result( c, RESULT_STACK, result_location );
     }
     else if ( parse->type == PARSE_RULES )
@@ -2427,28 +2696,31 @@
 
         switch ( parse->num )
         {
- case ASSIGN_SET: default: op_code = INSTR_SET; op_code_group = INSTR_SET_GROUP; break;
         case ASSIGN_APPEND: op_code = INSTR_APPEND; op_code_group = INSTR_APPEND_GROUP; break;
         case ASSIGN_DEFAULT: op_code = INSTR_DEFAULT; op_code_group = INSTR_DEFAULT_GROUP; break;
+ default: op_code = INSTR_SET; op_code_group = INSTR_SET_GROUP; break;
         }
 
- /*
- * Check whether there is exactly one variable
- * with a constant name
- */
+ /* Check whether there is exactly one variable with a constant name. */
         if ( vars->type == PARSE_LIST )
         {
- const char * s = object_str( vars->string );
+ char const * s = object_str( vars->string );
             VAR_PARSE_GROUP * group;
             current_file = object_str( parse->file );
             current_line = parse->line;
             group = parse_expansion( &s );
- if ( group->elems->size == 1 &&
- dynamic_array_at( VAR_PARSE *, group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
+ if ( group->elems->size == 1 && dynamic_array_at( VAR_PARSE *,
+ group->elems, 0 )->type == VAR_PARSE_TYPE_STRING )
             {
- int name = compile_emit_constant( c, ( (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *, group->elems, 0 ) )->s );
+ int const name = compile_emit_constant( c, (
+ (VAR_PARSE_STRING *)dynamic_array_at( VAR_PARSE *,
+ group->elems, 0 ) )->s );
                 var_parse_group_free( group );
                 compile_parse( parse->right, c, RESULT_STACK );
+ if ( result_location != RESULT_NONE )
+ {
+ compile_emit( c, INSTR_SET_RESULT, 1 );
+ }
                 compile_emit( c, op_code, name );
             }
             else
@@ -2456,6 +2728,10 @@
                 var_parse_group_compile( group, c );
                 var_parse_group_free( group );
                 compile_parse( parse->right, c, RESULT_STACK );
+ if ( result_location != RESULT_NONE )
+ {
+ compile_emit( c, INSTR_SET_RESULT, 1 );
+ }
                 compile_emit( c, op_code_group, 0 );
             }
         }
@@ -2463,26 +2739,30 @@
         {
             compile_parse( parse->left, c, RESULT_STACK );
             compile_parse( parse->right, c, RESULT_STACK );
+ if ( result_location != RESULT_NONE )
+ {
+ compile_emit( c, INSTR_SET_RESULT, 1 );
+ }
             compile_emit( c, op_code_group, 0 );
         }
- adjust_result( c, RESULT_STACK, result_location );
+ if ( result_location != RESULT_NONE )
+ {
+ adjust_result( c, RESULT_RETURN, result_location );
+ }
     }
     else if ( parse->type == PARSE_SETCOMP )
     {
         int n_args;
         struct arg_list * args = arg_list_compile( parse->right, &n_args );
-
- int rule_id = compile_emit_rule( c, parse->string, parse->left, n_args, args, parse->num );
-
+ int const rule_id = compile_emit_rule( c, parse->string, parse->left,
+ n_args, args, parse->num );
         compile_emit( c, INSTR_RULE, rule_id );
         adjust_result( c, RESULT_NONE, result_location );
     }
     else if ( parse->type == PARSE_SETEXEC )
     {
- int actions_id = compile_emit_actions( c, parse );
-
+ int const actions_id = compile_emit_actions( c, parse );
         compile_parse( parse->left, c, RESULT_STACK );
-
         compile_emit( c, INSTR_ACTIONS, actions_id );
         adjust_result( c, RESULT_NONE, result_location );
     }
@@ -2494,22 +2774,22 @@
 
         switch ( parse->num )
         {
- case ASSIGN_SET: default: compile_emit( c, INSTR_SET_ON, 0 ); break;
             case ASSIGN_APPEND: compile_emit( c, INSTR_APPEND_ON, 0 ); break;
             case ASSIGN_DEFAULT: compile_emit( c, INSTR_DEFAULT_ON, 0 ); break;
+ default: compile_emit( c, INSTR_SET_ON, 0 ); break;
         }
 
         adjust_result( c, RESULT_STACK, result_location );
     }
- else if ( parse->type == PARSE_SWITCH )
+ else if ( parse->type == PARSE_SWITCH )
     {
- int switch_end = compile_new_label( c );
+ int const switch_end = compile_new_label( c );
         compile_parse( parse->left, c, RESULT_STACK );
 
         for ( parse = parse->right; parse; parse = parse->right )
         {
- int id = compile_emit_constant( c, parse->left->string );
- int next_case = compile_new_label( c );
+ int const id = compile_emit_constant( c, parse->left->string );
+ int const next_case = compile_new_label( c );
             compile_emit( c, INSTR_PUSH_CONSTANT, id );
             compile_emit_branch( c, INSTR_JUMP_NOT_GLOB, next_case );
             compile_parse( parse->left->left, c, result_location );
@@ -2521,13 +2801,9 @@
         compile_set_label( c, switch_end );
     }
     else if ( parse->type == PARSE_NULL )
- {
         adjust_result( c, RESULT_NONE, result_location );
- }
     else
- {
         assert( !"unknown PARSE type." );
- }
 }
 
 OBJECT * function_rulename( FUNCTION * function )
@@ -2563,15 +2839,18 @@
     }
 }
 
-static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments );
+static struct arg_list * arg_list_compile_builtin( char const * * args,
+ int * num_arguments );
 
-FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * args )
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ),
+ int flags, char const * * args )
 {
     BUILTIN_FUNCTION * result = BJAM_MALLOC( sizeof( BUILTIN_FUNCTION ) );
     result->base.type = FUNCTION_BUILTIN;
     result->base.reference_count = 1;
     result->base.rulename = 0;
- result->base.formal_arguments = arg_list_compile_builtin( args, &result->base.num_formal_arguments );
+ result->base.formal_arguments = arg_list_compile_builtin( args,
+ &result->base.num_formal_arguments );
     result->func = func;
     result->flags = flags;
     return (FUNCTION *)result;
@@ -2579,7 +2858,7 @@
 
 FUNCTION * function_compile( PARSE * parse )
 {
- compiler c[1];
+ compiler c[ 1 ];
     JAM_FUNCTION * result;
     compiler_init( c );
     compile_parse( parse, c, RESULT_RETURN );
@@ -2591,9 +2870,10 @@
     return (FUNCTION *)result;
 }
 
-FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line )
+FUNCTION * function_compile_actions( char const * actions, OBJECT * file,
+ int line )
 {
- compiler c[1];
+ compiler c[ 1 ];
     JAM_FUNCTION * result;
     VAR_PARSE_ACTIONS * parse;
     current_file = object_str( file );
@@ -2624,18 +2904,21 @@
  * specification.
  */
 
-int is_type_name( const char * s )
+int is_type_name( char const * s )
 {
- return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
- ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
+ return s[ 0 ] == TYPE_OPEN_DELIM && s[ strlen( s ) - 1 ] ==
+ TYPE_CLOSE_DELIM;
 }
 
-static void argument_error( const char * message, FUNCTION * procedure, FRAME * frame, OBJECT * arg )
-{ extern void print_source_line( FRAME * );
+static void argument_error( char const * message, FUNCTION * procedure,
+ FRAME * frame, OBJECT * arg )
+{
+ extern void print_source_line( FRAME * );
     LOL * actual = frame->args;
     backtrace_line( frame->prev );
     printf( "*** argument error\n* rule %s ( ", frame->rulename );
- argument_list_print( procedure->formal_arguments, procedure->num_formal_arguments );
+ argument_list_print( procedure->formal_arguments,
+ procedure->num_formal_arguments );
     printf( " )\n* called with: ( " );
     lol_print( actual );
     printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" );
@@ -2646,15 +2929,8 @@
     exit( 1 );
 }
 
-static void type_check_range
-(
- OBJECT * type_name,
- LISTITER iter,
- LISTITER end,
- FRAME * caller,
- FUNCTION * called,
- OBJECT * arg_name
-)
+static void type_check_range( OBJECT * type_name, LISTITER iter, LISTITER end,
+ FRAME * caller, FUNCTION * called, OBJECT * arg_name )
 {
     static module_t * typecheck = 0;
 
@@ -2663,9 +2939,7 @@
         return;
 
     if ( !typecheck )
- {
         typecheck = bindmodule( constant_typecheck );
- }
 
     /* If the checking rule can not be found, also bail. */
     if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
@@ -2673,56 +2947,60 @@
 
     for ( ; iter != end; iter = list_next( iter ) )
     {
- LIST *error;
- FRAME frame[1];
+ LIST * error;
+ FRAME frame[ 1 ];
         frame_init( frame );
         frame->module = typecheck;
         frame->prev = caller;
- frame->prev_user = caller->module->user_module ? caller : caller->prev_user;
+ frame->prev_user = caller->module->user_module
+ ? caller
+ : caller->prev_user;
 
         /* Prepare the argument list */
         lol_add( frame->args, list_new( object_copy( list_item( iter ) ) ) );
- error = evaluate_rule( type_name, frame );
+ error = evaluate_rule( bindrule( type_name, frame->module ), type_name, frame );
 
         if ( !list_empty( error ) )
- argument_error( object_str( list_front( error ) ), called, caller, arg_name );
+ argument_error( object_str( list_front( error ) ), called, caller,
+ arg_name );
 
         frame_free( frame );
     }
 }
 
-static void type_check
-(
- OBJECT * type_name,
- LIST * values,
- FRAME * caller,
- FUNCTION * called,
- OBJECT * arg_name
-)
+static void type_check( OBJECT * type_name, LIST * values, FRAME * caller,
+ FUNCTION * called, OBJECT * arg_name )
 {
- type_check_range( type_name, list_begin( values ), list_end( values ), caller, called, arg_name );
+ type_check_range( type_name, list_begin( values ), list_end( values ),
+ caller, called, arg_name );
 }
 
-void argument_list_check( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame )
+void argument_list_check( struct arg_list * formal, int formal_count,
+ FUNCTION * function, FRAME * frame )
 {
     LOL * all_actual = frame->args;
- int i, j;
+ int i;
 
     for ( i = 0; i < formal_count; ++i )
     {
- LIST *actual = lol_get( all_actual, i );
- LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
- for ( j = 0; j < formal[i].size; ++j )
+ LIST * actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual );
+ LISTITER const actual_end = list_end( actual );
+ int j;
+ for ( j = 0; j < formal[ i ].size; ++j )
         {
- struct argument * formal_arg = &formal[i].args[j];
+ struct argument * formal_arg = &formal[ i ].args[ j ];
             LIST * value;
 
             switch ( formal_arg->flags )
             {
             case ARG_ONE:
                 if ( actual_iter == actual_end )
- argument_error( "missing argument", function, frame, formal_arg->arg_name );
- type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ argument_error( "missing argument", function, frame,
+ formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter,
+ list_next( actual_iter ), frame, function,
+ formal_arg->arg_name );
                 actual_iter = list_next( actual_iter );
                 break;
             case ARG_OPTIONAL:
@@ -2730,16 +3008,20 @@
                     value = L0;
                 else
                 {
- type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter,
+ list_next( actual_iter ), frame, function,
+ formal_arg->arg_name );
                     actual_iter = list_next( actual_iter );
                 }
                 break;
             case ARG_PLUS:
                 if ( actual_iter == actual_end )
- argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ argument_error( "missing argument", function, frame,
+ formal_arg->arg_name );
                 /* fallthrough */
             case ARG_STAR:
- type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter,
+ actual_end, frame, function, formal_arg->arg_name );
                 actual_iter = actual_end;
                 break;
             case ARG_VARIADIC:
@@ -2748,40 +3030,42 @@
         }
 
         if ( actual_iter != actual_end )
- {
- argument_error( "extra argument", function, frame, list_item( actual_iter ) );
- }
+ argument_error( "extra argument", function, frame, list_item(
+ actual_iter ) );
     }
 
     for ( ; i < all_actual->count; ++i )
     {
         LIST * actual = lol_get( all_actual, i );
         if ( !list_empty( actual ) )
- {
- argument_error( "extra argument", function, frame, list_front( actual ) );
- }
+ argument_error( "extra argument", function, frame, list_front(
+ actual ) );
     }
 }
 
-void argument_list_push( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, STACK * s )
+void argument_list_push( struct arg_list * formal, int formal_count,
+ FUNCTION * function, FRAME * frame, STACK * s )
 {
     LOL * all_actual = frame->args;
- int i, j;
+ int i;
 
     for ( i = 0; i < formal_count; ++i )
     {
- LIST *actual = lol_get( all_actual, i );
- LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
- for ( j = 0; j < formal[i].size; ++j )
+ LIST * actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual );
+ LISTITER const actual_end = list_end( actual );
+ int j;
+ for ( j = 0; j < formal[ i ].size; ++j )
         {
- struct argument * formal_arg = &formal[i].args[j];
+ struct argument * formal_arg = &formal[ i ].args[ j ];
             LIST * value;
 
             switch ( formal_arg->flags )
             {
             case ARG_ONE:
                 if ( actual_iter == actual_end )
- argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ argument_error( "missing argument", function, frame,
+ formal_arg->arg_name );
                 value = list_new( object_copy( list_item( actual_iter ) ) );
                 actual_iter = list_next( actual_iter );
                 break;
@@ -2796,7 +3080,8 @@
                 break;
             case ARG_PLUS:
                 if ( actual_iter == actual_end )
- argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ argument_error( "missing argument", function, frame,
+ formal_arg->arg_name );
                 /* fallthrough */
             case ARG_STAR:
                 value = list_copy_range( actual, actual_iter, actual_end );
@@ -2806,61 +3091,59 @@
                 return;
             }
 
- type_check( formal_arg->type_name, value, frame, function, formal_arg->arg_name );
+ type_check( formal_arg->type_name, value, frame, function,
+ formal_arg->arg_name );
 
             if ( formal_arg->index != -1 )
             {
- LIST * * old = &frame->module->fixed_variables[ formal_arg->index ];
+ LIST * * const old = &frame->module->fixed_variables[
+ formal_arg->index ];
                 stack_push( s, *old );
                 *old = value;
             }
             else
- {
- stack_push( s, var_swap( frame->module, formal_arg->arg_name, value ) );
- }
+ stack_push( s, var_swap( frame->module, formal_arg->arg_name,
+ value ) );
         }
 
         if ( actual_iter != actual_end )
- {
- argument_error( "extra argument", function, frame, list_item( actual_iter ) );
- }
+ argument_error( "extra argument", function, frame, list_item(
+ actual_iter ) );
     }
 
     for ( ; i < all_actual->count; ++i )
     {
- LIST * actual = lol_get( all_actual, i );
+ LIST * const actual = lol_get( all_actual, i );
         if ( !list_empty( actual ) )
- {
- argument_error( "extra argument", function, frame, list_front( actual ) );
- }
+ argument_error( "extra argument", function, frame, list_front(
+ actual ) );
     }
 }
 
-void argument_list_pop( struct arg_list * formal, int formal_count, FRAME * frame, STACK * s )
+void argument_list_pop( struct arg_list * formal, int formal_count,
+ FRAME * frame, STACK * s )
 {
- int i, j;
-
+ int i;
     for ( i = formal_count - 1; i >= 0; --i )
     {
- for ( j = formal[i].size - 1; j >= 0 ; --j )
+ int j;
+ for ( j = formal[ i ].size - 1; j >= 0 ; --j )
         {
- struct argument * formal_arg = &formal[i].args[j];
+ struct argument * formal_arg = &formal[ i ].args[ j ];
 
             if ( formal_arg->flags == ARG_VARIADIC )
- {
                 continue;
- }
- else if ( formal_arg->index != -1 )
+ if ( formal_arg->index != -1 )
             {
- LIST * old = stack_pop( s );
- LIST * * pos = &frame->module->fixed_variables[ formal_arg->index ];
+ LIST * const old = stack_pop( s );
+ LIST * * const pos = &frame->module->fixed_variables[
+ formal_arg->index ];
                 list_free( *pos );
                 *pos = old;
             }
             else
- {
- var_set( frame->module, formal_arg->arg_name, stack_pop( s ), VAR_SET );
- }
+ var_set( frame->module, formal_arg->arg_name, stack_pop( s ),
+ VAR_SET );
         }
     }
 }
@@ -2889,7 +3172,8 @@
     dynamic_array_free( c->args );
 }
 
-static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg, OBJECT * file, int line )
+static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg,
+ OBJECT * file, int line )
 {
     switch ( c->state )
     {
@@ -2930,13 +3214,14 @@
         /* fall-through */
 
     case ARGUMENT_COMPILER_FOUND_TYPE:
-
+
         if ( is_type_name( object_str( arg ) ) )
         {
- printf( "%s:%d: missing argument name before type name: %s\n", object_str( file ), line, object_str( arg ) );
+ printf( "%s:%d: missing argument name before type name: %s\n",
+ object_str( file ), line, object_str( arg ) );
             exit( 1 );
         }
-
+
         c->arg.arg_name = object_copy( arg );
         if ( object_equal( arg, constant_star ) )
         {
@@ -2955,7 +3240,8 @@
     }
 }
 
-static void argument_compiler_recurse( struct argument_compiler * c, PARSE * parse )
+static void argument_compiler_recurse( struct argument_compiler * c,
+ PARSE * parse )
 {
     if ( parse->type == PARSE_APPEND )
     {
@@ -2969,7 +3255,8 @@
     }
 }
 
-static struct arg_list arg_compile_impl( struct argument_compiler * c, OBJECT * file, int line )
+static struct arg_list arg_compile_impl( struct argument_compiler * c,
+ OBJECT * file, int line )
 {
     struct arg_list result;
     switch ( c->state )
@@ -2978,7 +3265,8 @@
     case ARGUMENT_COMPILER_DONE:
         break;
     case ARGUMENT_COMPILER_FOUND_TYPE:
- printf( "%s:%d: missing argument name after type name: %s\n", object_str( file ), line, object_str( c->arg.type_name ) );
+ printf( "%s:%d: missing argument name after type name: %s\n",
+ object_str( file ), line, object_str( c->arg.type_name ) );
         exit( 1 );
     case ARGUMENT_COMPILER_FOUND_OBJECT:
         dynamic_array_push( c->args, c->arg );
@@ -2986,7 +3274,8 @@
     }
     result.size = c->args->size;
     result.args = BJAM_MALLOC( c->args->size * sizeof( struct argument ) );
- memcpy( result.args, c->args->data, c->args->size * sizeof( struct argument ) );
+ memcpy( result.args, c->args->data, c->args->size * sizeof( struct argument
+ ) );
     return result;
 }
 
@@ -3016,13 +3305,15 @@
     dynamic_array_free( c->args );
 }
 
-static void argument_list_compiler_add( struct argument_list_compiler * c, PARSE * parse )
+static void argument_list_compiler_add( struct argument_list_compiler * c,
+ PARSE * parse )
 {
     struct arg_list args = arg_compile( parse );
     dynamic_array_push( c->args, args );
 }
 
-static void argument_list_compiler_recurse( struct argument_list_compiler * c, PARSE * parse )
+static void argument_list_compiler_recurse( struct argument_list_compiler * c,
+ PARSE * parse )
 {
     if ( parse )
     {
@@ -3041,18 +3332,17 @@
         argument_list_compiler_recurse( c, parse );
         *num_arguments = c->args->size;
         result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
- memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list )
+ );
         argument_list_compiler_free( c );
         return result;
     }
- else
- {
- *num_arguments = 0;
- return 0;
- }
+ *num_arguments = 0;
+ return 0;
 }
 
-static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments )
+static struct arg_list * arg_list_compile_builtin( char const * * args,
+ int * num_arguments )
 {
     if ( args )
     {
@@ -3082,32 +3372,32 @@
         }
         *num_arguments = c->args->size;
         result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
- memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list )
+ );
         argument_list_compiler_free( c );
         return result;
     }
- else
- {
- *num_arguments = 0;
- return 0;
- }
+ *num_arguments = 0;
+ return 0;
 }
 
 static void argument_list_print( struct arg_list * args, int num_args )
 {
     if ( args )
     {
- int i, j;
+ int i;
         for ( i = 0; i < num_args; ++i )
         {
- if ( i ) printf(" : ");
+ int j;
+ if ( i ) printf( " : " );
             for ( j = 0; j < args[ i ].size; ++j )
             {
                 struct argument * formal_arg = &args[ i ].args[ j ];
                 if ( j ) printf( " " );
- if ( formal_arg->type_name ) printf( "%s ", object_str( formal_arg->type_name ) );
- printf( "%s", formal_arg->arg_name );
- switch( formal_arg->flags )
+ if ( formal_arg->type_name )
+ printf( "%s ", object_str( formal_arg->type_name ) );
+ printf( "%s", object_str( formal_arg->arg_name ) );
+ switch ( formal_arg->flags )
                 {
                 case ARG_OPTIONAL: printf( " ?" ); break;
                 case ARG_PLUS: printf( " +" ); break;
@@ -3119,16 +3409,20 @@
 }
 
 
-struct arg_list * argument_list_bind_variables( struct arg_list * formal, int formal_count, module_t * module, int * counter )
+struct arg_list * argument_list_bind_variables( struct arg_list * formal,
+ int formal_count, module_t * module, int * counter )
 {
     if ( formal )
     {
- struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof( struct arg_list ) * formal_count );
- int i, j;
+ struct arg_list * result = (struct arg_list *)BJAM_MALLOC( sizeof(
+ struct arg_list ) * formal_count );
+ int i;
 
         for ( i = 0; i < formal_count; ++i )
         {
- struct argument * args = (struct argument *)BJAM_MALLOC( sizeof( struct argument ) * formal[ i ].size );
+ int j;
+ struct argument * args = (struct argument *)BJAM_MALLOC( sizeof(
+ struct argument ) * formal[ i ].size );
             for ( j = 0; j < formal[ i ].size; ++j )
             {
                 args[ j ] = formal[ i ].args[ j ];
@@ -3136,28 +3430,25 @@
                     args[ j ].type_name = object_copy( args[ j ].type_name );
                 args[ j ].arg_name = object_copy( args[ j ].arg_name );
                 if ( args[ j ].flags != ARG_VARIADIC )
- {
- args[ j ].index = module_add_fixed_var( module, args[ j ].arg_name, counter );
- }
+ args[ j ].index = module_add_fixed_var( module,
+ args[ j ].arg_name, counter );
             }
             result[ i ].args = args;
             result[ i ].size = formal[ i ].size;
         }
-
+
         return result;
     }
- else
- {
- return 0;
- }
+ return 0;
 }
 
 
 void argument_list_free( struct arg_list * args, int args_count )
 {
- int i, j;
+ int i;
     for ( i = 0; i < args_count; ++i )
     {
+ int j;
         for ( j = 0; j < args[ i ].size; ++j )
         {
             if ( args[ i ].args[ j ].type_name )
@@ -3174,38 +3465,26 @@
 {
     if ( f->type == FUNCTION_JAM )
     {
- JAM_FUNCTION * func = (JAM_FUNCTION *)f;
- if ( func->generic )
- return func->generic;
- else
- return (FUNCTION *)func;
+ JAM_FUNCTION * const func = (JAM_FUNCTION *)f;
+ return func->generic ? func->generic : f;
     }
 #ifdef HAVE_PYTHON
- else if ( f->type == FUNCTION_PYTHON )
- {
+ if ( f->type == FUNCTION_PYTHON )
         return f;
- }
 #endif
- else
- {
- assert( f->type == FUNCTION_BUILTIN );
- return f;
- }
+ assert( f->type == FUNCTION_BUILTIN );
+ return f;
 }
 
-FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter )
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module,
+ int * counter )
 {
     if ( f->type == FUNCTION_BUILTIN )
- {
         return f;
- }
 #ifdef HAVE_PYTHON
- else if ( f->type == FUNCTION_PYTHON )
- {
+ if ( f->type == FUNCTION_PYTHON )
         return f;
- }
 #endif
- else
     {
         JAM_FUNCTION * func = (JAM_FUNCTION *)f;
         JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
@@ -3214,9 +3493,11 @@
         assert( f->type == FUNCTION_JAM );
         memcpy( new_func, func, sizeof( JAM_FUNCTION ) );
         new_func->base.reference_count = 1;
- new_func->base.formal_arguments = argument_list_bind_variables( f->formal_arguments, f->num_formal_arguments, module, counter );
+ new_func->base.formal_arguments = argument_list_bind_variables(
+ f->formal_arguments, f->num_formal_arguments, module, counter );
         new_func->code = BJAM_MALLOC( func->code_size * sizeof( instruction ) );
- memcpy( new_func->code, func->code, func->code_size * sizeof( instruction ) );
+ memcpy( new_func->code, func->code, func->code_size * sizeof(
+ instruction ) );
         new_func->generic = (FUNCTION *)func;
         func = new_func;
         for ( i = 0; ; ++i )
@@ -3233,6 +3514,7 @@
             case INSTR_APPEND: op_code = INSTR_APPEND_FIXED; break;
             case INSTR_DEFAULT: op_code = INSTR_DEFAULT_FIXED; break;
             case INSTR_RETURN: return (FUNCTION *)new_func;
+ case INSTR_CALL_MEMBER_RULE:
             case INSTR_CALL_RULE: ++i; continue;
             case INSTR_PUSH_MODULE:
                 {
@@ -3283,9 +3565,12 @@
 {
     int i;
 
- if ( --function_->reference_count != 0 ) return;
-
- if ( function_->formal_arguments ) argument_list_free( function_->formal_arguments, function_->num_formal_arguments );
+ if ( --function_->reference_count != 0 )
+ return;
+
+ if ( function_->formal_arguments )
+ argument_list_free( function_->formal_arguments,
+ function_->num_formal_arguments );
 
     if ( function_->type == FUNCTION_JAM )
     {
@@ -3300,22 +3585,20 @@
             if ( function_->rulename ) object_free( function_->rulename );
 
             for ( i = 0; i < func->num_constants; ++i )
- {
- object_free( func->constants[i] );
- }
+ object_free( func->constants[ i ] );
             BJAM_FREE( func->constants );
 
             for ( i = 0; i < func->num_subfunctions; ++i )
             {
- object_free( func->functions[i].name );
- function_free( func->functions[i].code );
+ object_free( func->functions[ i ].name );
+ function_free( func->functions[ i ].code );
             }
             BJAM_FREE( func->functions );
 
             for ( i = 0; i < func->num_subactions; ++i )
             {
- object_free( func->actions[i].name );
- function_free( func->actions[i].command );
+ object_free( func->actions[ i ].name );
+ function_free( func->actions[ i ].command );
             }
             BJAM_FREE( func->actions );
 
@@ -3360,7 +3643,8 @@
 static char check_ptr_size1[ sizeof(LIST *) <= sizeof(void *) ? 1 : -1 ];
 static char check_ptr_size2[ sizeof(char *) <= sizeof(void *) ? 1 : -1 ];
 
-void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out )
+void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s,
+ string * out )
 {
     *(string * *)stack_allocate( s, sizeof( string * ) ) = out;
     list_free( function_run( function, frame, s ) );
@@ -3368,9 +3652,8 @@
 }
 
 /*
- * WARNING: The instruction set is tuned for Jam and
- * is not really generic. Be especially careful about
- * stack push/pop.
+ * WARNING: The instruction set is tuned for Jam and is not really generic. Be
+ * especially careful about stack push/pop.
  */
 
 LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s )
@@ -3384,26 +3667,26 @@
 
     if ( function_->type == FUNCTION_BUILTIN )
     {
- BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ BUILTIN_FUNCTION const * const f = (BUILTIN_FUNCTION *)function_;
         if ( function_->formal_arguments )
- argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame );
+ argument_list_check( function_->formal_arguments,
+ function_->num_formal_arguments, function_, frame );
         return f->func( frame, f->flags );
     }
 
 #ifdef HAVE_PYTHON
-
     else if ( function_->type == FUNCTION_PYTHON )
     {
         PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_;
         return call_python_function( f, frame );
     }
-
 #endif
 
     assert( function_->type == FUNCTION_JAM );
-
+
     if ( function_->formal_arguments )
- argument_list_push( function_->formal_arguments, function_->num_formal_arguments, function_, frame, s );
+ argument_list_push( function_->formal_arguments,
+ function_->num_formal_arguments, function_, frame, s );
 
     function = (JAM_FUNCTION *)function_;
     code = function->code;
@@ -3417,10 +3700,8 @@
          */
 
         case INSTR_PUSH_EMPTY:
- {
             stack_push( s, L0 );
             break;
- }
 
         case INSTR_PUSH_CONSTANT:
         {
@@ -3430,184 +3711,149 @@
         }
 
         case INSTR_PUSH_ARG:
- {
             stack_push( s, frame_get_local( frame, code->arg ) );
             break;
- }
 
         case INSTR_PUSH_VAR:
- {
             stack_push( s, function_get_variable( function, frame, code->arg ) );
             break;
- }
 
         case INSTR_PUSH_VAR_FIXED:
- {
- stack_push( s, list_copy( frame->module->fixed_variables[ code->arg ] ) );
+ stack_push( s, list_copy( frame->module->fixed_variables[ code->arg
+ ] ) );
             break;
- }
 
         case INSTR_PUSH_GROUP:
         {
             LIST * value = L0;
- LISTITER iter, end;
+ LISTITER iter;
+ LISTITER end;
             l = stack_pop( s );
- for ( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
- {
- LIST * one = function_get_named_variable( function, frame, list_item( iter ) );
- value = list_append( value, one );
- }
+ for ( iter = list_begin( l ), end = list_end( l ); iter != end;
+ iter = list_next( iter ) )
+ value = list_append( value, function_get_named_variable(
+ function, frame, list_item( iter ) ) );
             list_free( l );
             stack_push( s, value );
             break;
         }
 
         case INSTR_PUSH_APPEND:
- {
             r = stack_pop( s );
             l = stack_pop( s );
             stack_push( s, list_append( l, r ) );
             break;
- }
 
         case INSTR_SWAP:
- {
             l = stack_top( s );
             stack_set( s, 0, stack_at( s, code->arg ) );
             stack_set( s, code->arg, l );
             break;
- }
 
         case INSTR_POP:
- {
             list_free( stack_pop( s ) );
             break;
- }
 
         /*
          * Branch instructions
          */
 
         case INSTR_JUMP:
- {
             code += code->arg;
             break;
- }
 
         case INSTR_JUMP_EMPTY:
- {
             l = stack_pop( s );
- if ( !list_cmp( l, L0 ) ) { code += code->arg; }
+ if ( !list_cmp( l, L0 ) ) code += code->arg;
             list_free( l );
             break;
- }
 
         case INSTR_JUMP_NOT_EMPTY:
- {
             l = stack_pop( s );
- if( list_cmp( l, L0 ) ) { code += code->arg; }
+ if ( list_cmp( l, L0 ) ) code += code->arg;
             list_free( l );
             break;
- }
 
         case INSTR_JUMP_LT:
- {
             r = stack_pop( s );
             l = stack_pop( s );
- if ( list_cmp( l, r ) < 0 ) { code += code->arg; }
+ if ( list_cmp( l, r ) < 0 ) code += code->arg;
             list_free( l );
             list_free( r );
             break;
- }
 
         case INSTR_JUMP_LE:
- {
             r = stack_pop( s );
             l = stack_pop( s );
- if ( list_cmp( l, r ) <= 0 ) { code += code->arg; }
+ if ( list_cmp( l, r ) <= 0 ) code += code->arg;
             list_free( l );
             list_free( r );
             break;
- }
 
         case INSTR_JUMP_GT:
- {
             r = stack_pop( s );
             l = stack_pop( s );
- if ( list_cmp( l, r ) > 0 ) { code += code->arg; }
+ if ( list_cmp( l, r ) > 0 ) code += code->arg;
             list_free( l );
             list_free( r );
             break;
- }
 
         case INSTR_JUMP_GE:
- {
             r = stack_pop( s );
             l = stack_pop( s );
- if ( list_cmp( l, r ) >= 0 ) { code += code->arg; }
+ if ( list_cmp( l, r ) >= 0 ) code += code->arg;
             list_free( l );
             list_free( r );
             break;
- }
 
         case INSTR_JUMP_EQ:
- {
             r = stack_pop( s );
             l = stack_pop( s );
- if( list_cmp( l, r ) == 0 ) { code += code->arg; }
+ if ( list_cmp( l, r ) == 0 ) code += code->arg;
             list_free( l );
             list_free( r );
             break;
- }
 
         case INSTR_JUMP_NE:
- {
             r = stack_pop(s);
             l = stack_pop(s);
- if( list_cmp(l, r) != 0 ) { code += code->arg; }
+ if ( list_cmp(l, r) != 0 ) code += code->arg;
             list_free(l);
             list_free(r);
             break;
- }
 
         case INSTR_JUMP_IN:
- {
             r = stack_pop(s);
             l = stack_pop(s);
- if ( list_is_sublist( l, r ) ) { code += code->arg; }
+ if ( list_is_sublist( l, r ) ) code += code->arg;
             list_free(l);
             list_free(r);
             break;
- }
 
         case INSTR_JUMP_NOT_IN:
- {
             r = stack_pop( s );
             l = stack_pop( s );
- if( !list_is_sublist( l, r ) ) { code += code->arg; }
+ if ( !list_is_sublist( l, r ) ) code += code->arg;
             list_free( l );
             list_free( r );
             break;
- }
 
         /*
          * For
          */
-
+
         case INSTR_FOR_INIT:
- {
             l = stack_top( s );
             *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) =
                 list_begin( l );
             break;
- }
-
+
         case INSTR_FOR_LOOP:
         {
             LISTITER iter = *(LISTITER *)stack_get( s );
             stack_deallocate( s, sizeof( LISTITER ) );
             l = stack_top( s );
- if( iter == list_end( l ) )
+ if ( iter == list_end( l ) )
             {
                 list_free( stack_pop( s ) );
                 code += code->arg;
@@ -3628,20 +3874,16 @@
 
         case INSTR_JUMP_NOT_GLOB:
         {
- const char * pattern;
- const char * match;
+ char const * pattern;
+ char const * match;
             l = stack_pop( s );
             r = stack_top( s );
- pattern = !list_empty( l ) ? object_str( list_front( l ) ) : "";
- match = !list_empty( r ) ? object_str( list_front( r ) ) : "";
- if( glob( pattern, match ) )
- {
+ pattern = list_empty( l ) ? "" : object_str( list_front( l ) );
+ match = list_empty( r ) ? "" : object_str( list_front( r ) );
+ if ( glob( pattern, match ) )
                 code += code->arg;
- }
             else
- {
                 list_free( stack_pop( s ) );
- }
             list_free( l );
             break;
         }
@@ -3651,25 +3893,24 @@
          */
 
         case INSTR_SET_RESULT:
- {
             list_free( result );
- result = stack_pop( s );
+ if ( !code->arg )
+ result = stack_pop( s );
+ else
+ result = list_copy( stack_top( s ) );
             break;
- }
 
         case INSTR_PUSH_RESULT:
- {
             stack_push( s, result );
             result = L0;
             break;
- }
 
         case INSTR_RETURN:
         {
             if ( function_->formal_arguments )
- argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s );
+ argument_list_pop( function_->formal_arguments,
+ function_->num_formal_arguments, frame, s );
 #ifndef NDEBUG
-
             if ( !( saved_stack == s->data ) )
             {
                 frame->file = function->file;
@@ -3691,15 +3932,14 @@
         case INSTR_PUSH_LOCAL:
         {
             LIST * value = stack_pop( s );
- stack_push( s, function_swap_variable( function, frame, code->arg, value ) );
+ stack_push( s, function_swap_variable( function, frame, code->arg,
+ value ) );
             break;
         }
 
         case INSTR_POP_LOCAL:
- {
             function_set_variable( function, frame, code->arg, stack_pop( s ) );
             break;
- }
 
         case INSTR_PUSH_LOCAL_FIXED:
         {
@@ -3723,14 +3963,14 @@
 
         case INSTR_PUSH_LOCAL_GROUP:
         {
- LIST * value = stack_pop( s );
- LISTITER iter, end;
+ LIST * const value = stack_pop( s );
+ LISTITER iter;
+ LISTITER end;
             l = stack_pop( s );
- for( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
- {
- LIST * saved = function_swap_named_variable( function, frame, list_item( iter ), list_copy( value ) );
- stack_push( s, saved );
- }
+ for ( iter = list_begin( l ), end = list_end( l ); iter != end;
+ iter = list_next( iter ) )
+ stack_push( s, function_swap_named_variable( function, frame,
+ list_item( iter ), list_copy( value ) ) );
             list_free( value );
             stack_push( s, l );
             break;
@@ -3738,14 +3978,15 @@
 
         case INSTR_POP_LOCAL_GROUP:
         {
- LISTITER iter, end;
+ LISTITER iter;
+ LISTITER end;
             r = stack_pop( s );
             l = list_reverse( r );
             list_free( r );
- for( iter = list_begin( l ), end = list_end( l ); iter != end; iter = list_next( iter ) )
- {
- function_set_named_variable( function, frame, list_item( iter ), stack_pop( s ) );
- }
+ for ( iter = list_begin( l ), end = list_end( l ); iter != end;
+ iter = list_next( iter ) )
+ function_set_named_variable( function, frame, list_item( iter ),
+ stack_pop( s ) );
             list_free( l );
             break;
         }
@@ -3759,18 +4000,15 @@
             LIST * targets = stack_top( s );
             if ( !list_empty( targets ) )
             {
- /*
- * FIXME: push the state onto the stack instead of
- * using pushsettings.
+ /* FIXME: push the state onto the stack instead of using
+ * pushsettings.
                  */
                 TARGET * t = bindtarget( list_front( targets ) );
                 pushsettings( frame->module, t->settings );
             }
             else
             {
- /*
- * [ on $(TARGET) ... ] is ignored if $(TARGET) is empty.
- */
+ /* [ on $(TARGET) ... ] is ignored if $(TARGET) is empty. */
                 list_free( stack_pop( s ) );
                 stack_push( s, L0 );
                 code += code->arg;
@@ -3797,15 +4035,17 @@
             LIST * targets = stack_pop( s );
             LIST * value = stack_pop( s );
             LIST * vars = stack_pop( s );
- LISTITER iter = list_begin( targets ), end = list_end( targets );
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
             for ( ; iter != end; iter = list_next( iter ) )
             {
                 TARGET * t = bindtarget( list_item( iter ) );
- LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
-
- for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
- t->settings = addsettings( t->settings, VAR_SET, list_item( vars_iter ),
- list_copy( value ) );
+ LISTITER vars_iter = list_begin( vars );
+ LISTITER const vars_end = list_end( vars );
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter
+ ) )
+ t->settings = addsettings( t->settings, VAR_SET, list_item(
+ vars_iter ), list_copy( value ) );
             }
             list_free( vars );
             list_free( targets );
@@ -3818,15 +4058,17 @@
             LIST * targets = stack_pop( s );
             LIST * value = stack_pop( s );
             LIST * vars = stack_pop( s );
- LISTITER iter = list_begin( targets ), end = list_end( targets );
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
             for ( ; iter != end; iter = list_next( iter ) )
             {
- TARGET * t = bindtarget( list_item( iter ) );
- LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
-
- for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
- t->settings = addsettings( t->settings, VAR_APPEND, list_item( vars_iter ),
- list_copy( value ) );
+ TARGET * const t = bindtarget( list_item( iter ) );
+ LISTITER vars_iter = list_begin( vars );
+ LISTITER const vars_end = list_end( vars );
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter
+ ) )
+ t->settings = addsettings( t->settings, VAR_APPEND,
+ list_item( vars_iter ), list_copy( value ) );
             }
             list_free( vars );
             list_free( targets );
@@ -3839,15 +4081,17 @@
             LIST * targets = stack_pop( s );
             LIST * value = stack_pop( s );
             LIST * vars = stack_pop( s );
- LISTITER iter = list_begin( targets ), end = list_end( targets );
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
             for ( ; iter != end; iter = list_next( iter ) )
             {
                 TARGET * t = bindtarget( list_item( iter ) );
- LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
-
- for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
- t->settings = addsettings( t->settings, VAR_DEFAULT, list_item( vars_iter ),
- list_copy( value ) );
+ LISTITER vars_iter = list_begin( vars );
+ LISTITER const vars_end = list_end( vars );
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter
+ ) )
+ t->settings = addsettings( t->settings, VAR_DEFAULT,
+ list_item( vars_iter ), list_copy( value ) );
             }
             list_free( vars );
             list_free( targets );
@@ -3855,34 +4099,60 @@
             break;
         }
 
+ /* [ on $(target) return $(variable) ] */
+ case INSTR_GET_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * result = L0;
+ if ( !list_empty( targets ) )
+ {
+ OBJECT * varname = function->constants[ code->arg ];
+ TARGET * t = bindtarget( list_front( targets ) );
+ SETTINGS * s = t->settings;
+ int found = 0;
+ for ( ; s != 0; s = s->next )
+ {
+ if ( object_equal( s->symbol, varname ) )
+ {
+ result = s->value;
+ found = 1;
+ break;
+ }
+ }
+ if ( !found )
+ {
+ result = var_get( frame->module, varname ) ;
+ }
+ }
+ stack_push( s, list_copy( result ) );
+ break;
+ }
+
         /*
          * Variable setting
          */
 
         case INSTR_SET:
- {
- function_set_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ function_set_variable( function, frame, code->arg,
+ stack_pop( s ) );
             break;
- }
 
         case INSTR_APPEND:
- {
- function_append_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ function_append_variable( function, frame, code->arg,
+ stack_pop( s ) );
             break;
- }
 
         case INSTR_DEFAULT:
- {
- function_default_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ function_default_variable( function, frame, code->arg,
+ stack_pop( s ) );
             break;
- }
 
         case INSTR_SET_FIXED:
         {
             LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
             assert( code->arg < frame->module->num_fixed_variables );
             list_free( *ptr );
- *ptr = list_copy( stack_top( s ) );
+ *ptr = stack_pop( s );
             break;
         }
 
@@ -3890,16 +4160,19 @@
         {
             LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
             assert( code->arg < frame->module->num_fixed_variables );
- *ptr = list_append( *ptr, list_copy( stack_top( s ) ) );
+ *ptr = list_append( *ptr, stack_pop( s ) );
             break;
         }
 
         case INSTR_DEFAULT_FIXED:
         {
             LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ LIST * value = stack_pop( s );
             assert( code->arg < frame->module->num_fixed_variables );
             if ( list_empty( *ptr ) )
- *ptr = list_copy( stack_top( s ) );
+ *ptr = value;
+ else
+ list_free( value );
             break;
         }
 
@@ -3907,11 +4180,13 @@
         {
             LIST * value = stack_pop( s );
             LIST * vars = stack_pop( s );
- LISTITER iter = list_begin( vars ), end = list_end( vars );
- for( ; iter != end; iter = list_next( iter ) )
- function_set_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ LISTITER iter = list_begin( vars );
+ LISTITER const end = list_end( vars );
+ for ( ; iter != end; iter = list_next( iter ) )
+ function_set_named_variable( function, frame, list_item( iter ),
+ list_copy( value ) );
             list_free( vars );
- stack_push( s, value );
+ list_free( value );
             break;
         }
 
@@ -3919,11 +4194,13 @@
         {
             LIST * value = stack_pop( s );
             LIST * vars = stack_pop( s );
- LISTITER iter = list_begin( vars ), end = list_end( vars );
- for( ; iter != end; iter = list_next( iter ) )
- function_append_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ LISTITER iter = list_begin( vars );
+ LISTITER const end = list_end( vars );
+ for ( ; iter != end; iter = list_next( iter ) )
+ function_append_named_variable( function, frame, list_item( iter
+ ), list_copy( value ) );
             list_free( vars );
- stack_push( s, value );
+ list_free( value );
             break;
         }
 
@@ -3931,11 +4208,13 @@
         {
             LIST * value = stack_pop( s );
             LIST * vars = stack_pop( s );
- LISTITER iter = list_begin( vars ), end = list_end( vars );
- for( ; iter != end; iter = list_next( iter ) )
- function_default_named_variable( function, frame, list_item( iter ), list_copy( value ) );
+ LISTITER iter = list_begin( vars );
+ LISTITER const end = list_end( vars );
+ for ( ; iter != end; iter = list_next( iter ) )
+ function_default_named_variable( function, frame, list_item(
+ iter ), list_copy( value ) );
             list_free( vars );
- stack_push( s, value );
+ list_free( value );
             break;
         }
 
@@ -3945,25 +4224,31 @@
 
         case INSTR_CALL_RULE:
         {
- const char * unexpanded =
- object_str( function_get_constant( function, code[1].op_code ) );
- LIST * result = function_call_rule( function, frame, s, code->arg, unexpanded, function->file, code[1].arg );
+ char const * unexpanded = object_str( function_get_constant(
+ function, code[ 1 ].op_code ) );
+ LIST * result = function_call_rule( function, frame, s, code->arg,
+ unexpanded, function->file, code[ 1 ].arg );
             stack_push( s, result );
             ++code;
             break;
         }
 
- case INSTR_RULE:
+ case INSTR_CALL_MEMBER_RULE:
         {
- function_set_rule( function, frame, s, code->arg );
+ OBJECT * rule_name = function_get_constant( function, code[1].op_code );
+ LIST * result = function_call_member_rule( function, frame, s, code->arg, rule_name, function->file, code[1].arg );
+ stack_push( s, result );
+ ++code;
             break;
         }
 
+ case INSTR_RULE:
+ function_set_rule( function, frame, s, code->arg );
+ break;
+
         case INSTR_ACTIONS:
- {
             function_set_actions( function, frame, s, code->arg );
             break;
- }
 
         /*
          * Variable expansion
@@ -3980,20 +4265,18 @@
             list_free( stack_pop( s ) );
             stack_deallocate( s, n * sizeof( VAR_EDITS ) );
             for ( i = 0; i < code->arg; ++i )
- list_free( stack_pop( s ) ); /* pop modifiers */
+ list_free( stack_pop( s ) ); /* pop modifiers */
             stack_push( s, l );
             break;
         }
-
+
         case INSTR_APPLY_INDEX:
- {
             l = apply_subscript( s );
             list_free( stack_pop( s ) );
             list_free( stack_pop( s ) );
             stack_push( s, l );
             break;
- }
-
+
         case INSTR_APPLY_INDEX_MODIFIERS:
         {
             int i;
@@ -4008,7 +4291,7 @@
             list_free( stack_pop( s ) );
             stack_deallocate( s, n * sizeof( VAR_EDITS ) );
             for ( i = 0; i < code->arg; ++i )
- list_free( stack_pop( s ) ); /* pop modifiers */
+ list_free( stack_pop( s ) ); /* pop modifiers */
             stack_push( s, l );
             break;
         }
@@ -4016,32 +4299,36 @@
         case INSTR_APPLY_MODIFIERS_GROUP:
         {
             int i;
- LIST * vars = stack_pop( s );
- int n = expand_modifiers( s, code->arg );
+ LIST * const vars = stack_pop( s );
+ int const n = expand_modifiers( s, code->arg );
             LIST * result = L0;
- LISTITER iter = list_begin( vars ), end = list_end( vars );
- for( ; iter != end; iter = list_next( iter ) )
+ LISTITER iter = list_begin( vars );
+ LISTITER const end = list_end( vars );
+ for ( ; iter != end; iter = list_next( iter ) )
             {
- stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ stack_push( s, function_get_named_variable( function, frame,
+ list_item( iter ) ) );
                 result = list_append( result, apply_modifiers( s, n ) );
                 list_free( stack_pop( s ) );
             }
             list_free( vars );
             stack_deallocate( s, n * sizeof( VAR_EDITS ) );
             for ( i = 0; i < code->arg; ++i )
- list_free( stack_pop( s ) ); /* pop modifiers */
+ list_free( stack_pop( s ) ); /* pop modifiers */
             stack_push( s, result );
             break;
         }
-
+
         case INSTR_APPLY_INDEX_GROUP:
         {
             LIST * vars = stack_pop( s );
             LIST * result = L0;
- LISTITER iter = list_begin( vars ), end = list_end( vars );
- for( ; iter != end; iter = list_next( iter ) )
+ LISTITER iter = list_begin( vars );
+ LISTITER const end = list_end( vars );
+ for ( ; iter != end; iter = list_next( iter ) )
             {
- stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ stack_push( s, function_get_named_variable( function, frame,
+ list_item( iter ) ) );
                 result = list_append( result, apply_subscript( s ) );
                 list_free( stack_pop( s ) );
             }
@@ -4050,49 +4337,77 @@
             stack_push( s, result );
             break;
         }
-
+
         case INSTR_APPLY_INDEX_MODIFIERS_GROUP:
         {
             int i;
- LIST * vars = stack_pop( s );
- LIST * r = stack_pop( s );
- int n = expand_modifiers( s, code->arg );
+ LIST * const vars = stack_pop( s );
+ LIST * const r = stack_pop( s );
+ int const n = expand_modifiers( s, code->arg );
             LIST * result = L0;
- LISTITER iter = list_begin( vars ), end = list_end( vars );
+ LISTITER iter = list_begin( vars );
+ LISTITER const end = list_end( vars );
             stack_push( s, r );
- for( ; iter != end; iter = list_next( iter ) )
+ for ( ; iter != end; iter = list_next( iter ) )
             {
- stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
- result = list_append( result, apply_subscript_and_modifiers( s, n ) );
+ stack_push( s, function_get_named_variable( function, frame,
+ list_item( iter ) ) );
+ result = list_append( result, apply_subscript_and_modifiers( s,
+ n ) );
                 list_free( stack_pop( s ) );
             }
             list_free( stack_pop( s ) );
             list_free( vars );
             stack_deallocate( s, n * sizeof( VAR_EDITS ) );
             for ( i = 0; i < code->arg; ++i )
- list_free( stack_pop( s ) ); /* pop modifiers */
+ list_free( stack_pop( s ) ); /* pop modifiers */
             stack_push( s, result );
             break;
         }
 
         case INSTR_COMBINE_STRINGS:
         {
- LIST * result;
- size_t buffer_size = code->arg * sizeof( expansion_item );
- LIST * * stack_pos = stack_get( s );
+ size_t const buffer_size = code->arg * sizeof( expansion_item );
+ LIST * * const stack_pos = stack_get( s );
             expansion_item * items = stack_allocate( s, buffer_size );
+ LIST * result;
             int i;
- for( i = 0; i < code->arg; ++i )
- {
- items[i].saved = stack_pos[i];
- items[i].elem = list_begin( items[i].saved );
- }
+ for ( i = 0; i < code->arg; ++i )
+ items[ i ].values = stack_pos[ i ];
             result = expand( items, code->arg );
             stack_deallocate( s, buffer_size );
- for( i = 0; i < code->arg; ++i )
- {
+ for ( i = 0; i < code->arg; ++i )
                 list_free( stack_pop( s ) );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_GET_GRIST:
+ {
+ LIST * vals = stack_pop( s );
+ LIST * result = L0;
+ LISTITER iter, end;
+
+ for ( iter = list_begin( vals ), end = list_end( vals ); iter != end; ++iter )
+ {
+ OBJECT * new_object;
+ const char * value = object_str( list_item( iter ) );
+ const char * p;
+ if ( value[ 0 ] == '<' && ( p = strchr( value, '>' ) ) )
+ {
+ if( p[ 1 ] )
+ new_object = object_new_range( value, p - value + 1 );
+ else
+ new_object = object_copy( list_item( iter ) );
+ }
+ else
+ {
+ new_object = object_copy( constant_empty );
+ }
+ result = list_push_back( result, new_object );
             }
+
+ list_free( vals );
             stack_push( s, result );
             break;
         }
@@ -4100,33 +4415,33 @@
         case INSTR_INCLUDE:
         {
             LIST * nt = stack_pop( s );
-
             if ( !list_empty( nt ) )
             {
- TARGET * t = bindtarget( list_front( nt ) );
+ TARGET * const t = bindtarget( list_front( nt ) );
                 list_free( nt );
 
- /* DWA 2001/10/22 - Perforce Jam cleared the arguments here, which
- * prevents an included file from being treated as part of the body of a
- * rule. I did not see any reason to do that, so I lifted the
- * restriction.
+ /* DWA 2001/10/22 - Perforce Jam cleared the arguments here,
+ * which prevented an included file from being treated as part
+ * of the body of a rule. I did not see any reason to do that,
+ * so I lifted the restriction.
                  */
 
- /* Bind the include file under the influence of */
- /* "on-target" variables. Though they are targets, */
- /* include files are not built with make(). */
+ /* Bind the include file under the influence of "on-target"
+ * variables. Though they are targets, include files are not
+ * built with make().
+ */
 
                 pushsettings( root_module(), t->settings );
- /* We don't expect that file to be included is generated by some
- action. Therefore, pass 0 as third argument.
- If the name resolves to directory, let it error out. */
+ /* We do not expect that a file to be included is generated by
+ * some action. Therefore, pass 0 as third argument. If the name
+ * resolves to a directory, let it error out.
+ */
                 object_free( t->boundname );
                 t->boundname = search( t->name, &t->time, 0, 0 );
                 popsettings( root_module(), t->settings );
 
                 parse_file( t->boundname, frame );
             }
-
             break;
         }
 
@@ -4136,21 +4451,20 @@
 
         case INSTR_PUSH_MODULE:
         {
- LIST * module_name = stack_pop( s );
-
- module_t * outer_module = frame->module;
- frame->module = !list_empty( module_name ) ? bindmodule( list_front( module_name ) ) : root_module();
-
+ LIST * const module_name = stack_pop( s );
+ module_t * const outer_module = frame->module;
+ frame->module = !list_empty( module_name )
+ ? bindmodule( list_front( module_name ) )
+ : root_module();
             list_free( module_name );
-
- *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
-
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) =
+ outer_module;
             break;
         }
 
         case INSTR_POP_MODULE:
         {
- module_t * outer_module = *(module_t * *)stack_get( s );
+ module_t * const outer_module = *(module_t * *)stack_get( s );
             stack_deallocate( s, sizeof( module_t * ) );
             frame->module = outer_module;
             break;
@@ -4162,35 +4476,33 @@
             LIST * name = stack_pop( s );
             OBJECT * class_module = make_class_module( name, bases, frame );
 
- module_t * outer_module = frame->module;
+ module_t * const outer_module = frame->module;
             frame->module = bindmodule( class_module );
             object_free( class_module );
-
- *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
 
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) =
+ outer_module;
             break;
         }
 
         case INSTR_BIND_MODULE_VARIABLES:
- {
             module_bind_variables( frame->module );
             break;
- }
-
+
         case INSTR_APPEND_STRINGS:
         {
- string buf[1];
+ string buf[ 1 ];
             string_new( buf );
             combine_strings( s, code->arg, buf );
             stack_push( s, list_new( object_new( buf->value ) ) );
             string_free( buf );
             break;
         }
-
+
         case INSTR_WRITE_FILE:
         {
- string buf[1];
- const char * out;
+ string buf[ 1 ];
+ char const * out;
             OBJECT * tmp_filename = 0;
             int out_debug = DEBUG_EXEC ? 1 : 0;
             FILE * out_file = 0;
@@ -4198,17 +4510,16 @@
             combine_strings( s, code->arg, buf );
             out = object_str( list_front( stack_top( s ) ) );
 
- /* For stdout/stderr we will create a temp file and generate
- * a command that outputs the content as needed.
- */
+ /* For stdout/stderr we will create a temp file and generate a
+ * command that outputs the content as needed.
+ */
             if ( ( strcmp( "STDOUT", out ) == 0 ) ||
                 ( strcmp( "STDERR", out ) == 0 ) )
             {
                 int err_redir = strcmp( "STDERR", out ) == 0;
- string result[1];
+ string result[ 1 ];
                 tmp_filename = path_tmpfile();
                 string_new( result );
-
                 #ifdef OS_NT
                 string_append( result, "type \"" );
                 #else
@@ -4226,40 +4537,36 @@
 
                 string_free( result );
 
- /* We also make sure that the temp files created by this
- * get nuked eventually.
- */
+ /* Make sure temp files created by this get nuked eventually. */
                 file_remove_atexit( tmp_filename );
             }
 
             if ( !globs.noexec )
             {
- string out_name[1];
+ string out_name[ 1 ];
                 /* Handle "path to file" filenames. */
- if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' ) )
+ if ( ( out[ 0 ] == '"' ) && ( out[ strlen( out ) - 1 ] == '"' )
+ )
                 {
                     string_copy( out_name, out + 1 );
                     string_truncate( out_name, out_name->size - 1 );
                 }
                 else
- {
                     string_copy( out_name, out );
- }
                 out_file = fopen( out_name->value, "w" );
-
+
                 if ( !out_file )
                 {
- printf( "failed to write output file '%s'!\n", out_name->value );
+ printf( "failed to write output file '%s'!\n",
+ out_name->value );
                     exit( EXITBAD );
                 }
                 string_free( out_name );
             }
 
             if ( out_debug ) printf( "\nfile %s\n", out );
-
             if ( out_file ) fputs( buf->value, out_file );
             if ( out_debug ) fputs( buf->value, stdout );
-
             if ( out_file )
             {
                 fflush( out_file );
@@ -4270,13 +4577,13 @@
                 object_free( tmp_filename );
 
             if ( out_debug ) fputc( '\n', stdout );
-
             break;
         }
 
         case INSTR_OUTPUT_STRINGS:
         {
- string * buf = *(string * *)( (char *)stack_get( s ) + ( code->arg * sizeof( LIST * ) ) );
+ string * const buf = *(string * *)( (char *)stack_get( s ) + (
+ code->arg * sizeof( LIST * ) ) );
             combine_strings( s, code->arg, buf );
             break;
         }
@@ -4289,13 +4596,15 @@
 
 #ifdef HAVE_PYTHON
 
-static struct arg_list * arg_list_compile_python( PyObject * bjam_signature, int * num_arguments )
+static struct arg_list * arg_list_compile_python( PyObject * bjam_signature,
+ int * num_arguments )
 {
     if ( bjam_signature )
     {
         struct argument_list_compiler c[ 1 ];
         struct arg_list * result;
- Py_ssize_t s, i, j, inner;
+ Py_ssize_t s;
+ Py_ssize_t i;
         argument_list_compiler_init( c );
 
         s = PySequence_Size( bjam_signature );
@@ -4304,15 +4613,15 @@
             struct argument_compiler arg_comp[ 1 ];
             struct arg_list arg;
             PyObject * v = PySequence_GetItem( bjam_signature, i );
+ Py_ssize_t j;
+ Py_ssize_t inner;
             argument_compiler_init( arg_comp );
-
+
             inner = PySequence_Size( v );
             for ( j = 0; j < inner; ++j )
- {
- PyObject * x = PySequence_GetItem( v, j );
- argument_compiler_add( arg_comp, object_new( PyString_AsString( x ) ), constant_builtin, -1 );
- }
-
+ argument_compiler_add( arg_comp, object_new( PyString_AsString(
+ PySequence_GetItem( v, j ) ) ), constant_builtin, -1 );
+
             arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
             dynamic_array_push( c->args, arg );
             argument_compiler_free( arg_comp );
@@ -4321,43 +4630,46 @@
 
         *num_arguments = c->args->size;
         result = BJAM_MALLOC( c->args->size * sizeof( struct arg_list ) );
- memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list ) );
+ memcpy( result, c->args->data, c->args->size * sizeof( struct arg_list )
+ );
         argument_list_compiler_free( c );
         return result;
     }
- else
- {
- *num_arguments = 0;
- return 0;
- }
+ *num_arguments = 0;
+ return 0;
 }
 
 FUNCTION * function_python( PyObject * function, PyObject * bjam_signature )
 {
     PYTHON_FUNCTION * result = BJAM_MALLOC( sizeof( PYTHON_FUNCTION ) );
-
+
     result->base.type = FUNCTION_PYTHON;
     result->base.reference_count = 1;
     result->base.rulename = 0;
- result->base.formal_arguments = arg_list_compile_python( bjam_signature, &result->base.num_formal_arguments );
+ result->base.formal_arguments = arg_list_compile_python( bjam_signature,
+ &result->base.num_formal_arguments );
     Py_INCREF( function );
     result->python_function = function;
 
     return (FUNCTION *)result;
 }
 
-static void argument_list_to_python( struct arg_list * formal, int formal_count, FUNCTION * function, FRAME * frame, PyObject * kw )
+
+static void argument_list_to_python( struct arg_list * formal, int formal_count,
+ FUNCTION * function, FRAME * frame, PyObject * kw )
 {
     LOL * all_actual = frame->args;
- int i, j;
+ int i;
 
     for ( i = 0; i < formal_count; ++i )
     {
- LIST *actual = lol_get( all_actual, i );
- LISTITER actual_iter = list_begin( actual ), actual_end = list_end( actual );
- for ( j = 0; j < formal[i].size; ++j )
+ LIST * actual = lol_get( all_actual, i );
+ LISTITER actual_iter = list_begin( actual );
+ LISTITER const actual_end = list_end( actual );
+ int j;
+ for ( j = 0; j < formal[ i ].size; ++j )
         {
- struct argument * formal_arg = &formal[i].args[j];
+ struct argument * formal_arg = &formal[ i ].args[ j ];
             PyObject * value;
             LIST * l;
 
@@ -4365,9 +4677,12 @@
             {
             case ARG_ONE:
                 if ( actual_iter == actual_end )
- argument_error( "missing argument", function, frame, formal_arg->arg_name );
- type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
- value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ argument_error( "missing argument", function, frame,
+ formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter, list_next(
+ actual_iter ), frame, function, formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item( actual_iter
+ ) ) );
                 actual_iter = list_next( actual_iter );
                 break;
             case ARG_OPTIONAL:
@@ -4375,17 +4690,22 @@
                     value = 0;
                 else
                 {
- type_check_range( formal_arg->type_name, actual_iter, list_next( actual_iter ), frame, function, formal_arg->arg_name );
- value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ type_check_range( formal_arg->type_name, actual_iter,
+ list_next( actual_iter ), frame, function,
+ formal_arg->arg_name );
+ value = PyString_FromString( object_str( list_item(
+ actual_iter ) ) );
                     actual_iter = list_next( actual_iter );
                 }
                 break;
             case ARG_PLUS:
                 if ( actual_iter == actual_end )
- argument_error( "missing argument", function, frame, formal_arg->arg_name );
+ argument_error( "missing argument", function, frame,
+ formal_arg->arg_name );
                 /* fallthrough */
             case ARG_STAR:
- type_check_range( formal_arg->type_name, actual_iter, actual_end, frame, function, formal_arg->arg_name );
+ type_check_range( formal_arg->type_name, actual_iter,
+ actual_end, frame, function, formal_arg->arg_name );
                 l = list_copy_range( actual, actual_iter, actual_end );
                 value = list_to_python( l );
                 list_free( l );
@@ -4394,10 +4714,11 @@
             case ARG_VARIADIC:
                 return;
             }
-
- if (value)
+
+ if ( value )
             {
- PyObject * key = PyString_FromString( object_str( formal_arg->arg_name ) );
+ PyObject * key = PyString_FromString( object_str(
+ formal_arg->arg_name ) );
                 PyDict_SetItem( kw, key, value );
                 Py_DECREF( key );
                 Py_DECREF( value );
@@ -4405,88 +4726,84 @@
         }
 
         if ( actual_iter != actual_end )
- {
- argument_error( "extra argument", function, frame, list_item( actual_iter ) );
- }
+ argument_error( "extra argument", function, frame, list_item(
+ actual_iter ) );
     }
 
     for ( ; i < all_actual->count; ++i )
     {
- LIST * actual = lol_get( all_actual, i );
+ LIST * const actual = lol_get( all_actual, i );
         if ( !list_empty( actual ) )
- {
- argument_error( "extra argument", function, frame, list_front( actual ) );
- }
+ argument_error( "extra argument", function, frame, list_front(
+ actual ) );
     }
 }
 
-/* Given a Python object, return a string to use in Jam
- code instead of said object.
- If the object is string, use the string value
- If the object implemenets __jam_repr__ method, use that.
- Otherwise return 0. */
+
+/* Given a Python object, return a string to use in Jam code instead of the said
+ * object.
+ *
+ * If the object is a string, use the string value.
+ * If the object implemenets __jam_repr__ method, use that.
+ * Otherwise return 0.
+ */
+
 OBJECT * python_to_string( PyObject * value )
 {
     if ( PyString_Check( value ) )
- {
- return object_new( PyString_AsString( value ) );
- }
- else
- {
- /* See if this is an instance that defines special __jam_repr__
- method. */
- if ( PyInstance_Check( value )
- && PyObject_HasAttrString( value, "__jam_repr__" ) )
- {
- PyObject* repr = PyObject_GetAttrString( value, "__jam_repr__" );
- if ( repr )
- {
- PyObject * arguments2 = PyTuple_New( 0 );
- PyObject * value2 = PyObject_Call( repr, arguments2, 0 );
- Py_DECREF( repr );
- Py_DECREF( arguments2 );
- if ( PyString_Check( value2 ) )
- {
- return object_new( PyString_AsString( value2 ) );
- }
- Py_DECREF( value2 );
- }
+ return object_new( PyString_AS_STRING( value ) );
+
+ /* See if this instance defines the special __jam_repr__ method. */
+ if ( PyInstance_Check( value )
+ && PyObject_HasAttrString( value, "__jam_repr__" ) )
+ {
+ PyObject * repr = PyObject_GetAttrString( value, "__jam_repr__" );
+ if ( repr )
+ {
+ PyObject * arguments2 = PyTuple_New( 0 );
+ PyObject * value2 = PyObject_Call( repr, arguments2, 0 );
+ Py_DECREF( repr );
+ Py_DECREF( arguments2 );
+ if ( PyString_Check( value2 ) )
+ return object_new( PyString_AS_STRING( value2 ) );
+ Py_DECREF( value2 );
         }
- return 0;
     }
+ return 0;
 }
 
+
 static module_t * python_module()
 {
     static module_t * python = 0;
     if ( !python )
- python = bindmodule(constant_python);
+ python = bindmodule( constant_python );
     return python;
 }
 
+
 static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame )
 {
     LIST * result = 0;
     PyObject * arguments = 0;
     PyObject * kw = NULL;
- int i ;
+ int i;
     PyObject * py_result;
     FRAME * prev_frame_before_python_call;
 
     if ( function->base.formal_arguments )
     {
- arguments = PyTuple_New(0);
+ arguments = PyTuple_New( 0 );
         kw = PyDict_New();
-
- argument_list_to_python( function->base.formal_arguments, function->base.num_formal_arguments, &function->base, frame, kw );
+ argument_list_to_python( function->base.formal_arguments,
+ function->base.num_formal_arguments, &function->base, frame, kw );
     }
     else
     {
         arguments = PyTuple_New( frame->args->count );
         for ( i = 0; i < frame->args->count; ++i )
- {
- PyTuple_SetItem( arguments, i, list_to_python( lol_get( frame->args, i ) ) );
- }
+ PyTuple_SetItem( arguments, i, list_to_python( lol_get( frame->args,
+ i ) ) );
     }
 
     frame->module = python_module();
@@ -4505,32 +4822,32 @@
             int i;
             for ( i = 0; i < size; ++i )
             {
- PyObject * item = PyList_GetItem( py_result, i );
- OBJECT *s = python_to_string( item );
- if ( !s ) {
- fprintf( stderr, "Non-string object returned by Python call.\n" );
- } else {
+ OBJECT * s = python_to_string( PyList_GetItem( py_result, i ) );
+ if ( !s )
+ fprintf( stderr,
+ "Non-string object returned by Python call.\n" );
+ else
                     result = list_push_back( result, s );
- }
             }
         }
         else if ( py_result == Py_None )
         {
             result = L0;
         }
- else
+ else
         {
- OBJECT *s = python_to_string( py_result );
- if (s)
+ OBJECT * const s = python_to_string( py_result );
+ if ( s )
                 result = list_new( s );
- else
- /* We have tried all we could. Return empty list. There are
- cases, e.g. feature.feature function that should return
- value for the benefit of Python code and which also can be
- called by Jam code, where no sensible value can be
- returned. We cannot even emit a warning, since there will
- be a pile of them. */
- result = L0;
+ else
+ /* We have tried all we could. Return empty list. There are
+ * cases, e.g. feature.feature function that should return a
+ * value for the benefit of Python code and which also can be
+ * called by Jam code, where no sensible value can be returned.
+ * We cannot even emit a warning, since there would be a pile of
+ * them.
+ */
+ result = L0;
         }
 
         Py_DECREF( py_result );
@@ -4538,7 +4855,7 @@
     else
     {
         PyErr_Print();
- fprintf( stderr,"Call failed\n" );
+ fprintf( stderr, "Call failed\n" );
     }
 
     return result;

Modified: branches/release/tools/build/v2/engine/hash.c
==============================================================================
--- branches/release/tools/build/v2/engine/hash.c (original)
+++ branches/release/tools/build/v2/engine/hash.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,124 +4,143 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-# include "jam.h"
-# include "hash.h"
-# include "compile.h"
-# include "object.h"
-# include <assert.h>
-
 /*
  * hash.c - simple in-memory hashing routines
  *
  * External routines:
- *
  * hashinit() - initialize a hash table, returning a handle
  * hashitem() - find a record in the table, and optionally enter a new one
  * hashdone() - free a hash table, given its handle
  *
  * Internal routines:
- *
  * hashrehash() - resize and rebuild hp->tab, the hash table
- *
- * 4/29/93 - ensure ITEM's are aligned
  */
 
+#include "jam.h"
+#include "hash.h"
+
+#include "compile.h"
+
+#include <assert.h>
+
 /* */
 #define HASH_DEBUG_PROFILE 1
 /* */
 
-/* Header attached to all data items entered into a hash table. */
+/* Header attached to all hash table data items. */
 
-struct hashhdr
+typedef struct item ITEM;
+struct item
 {
- struct item * next;
+ ITEM * next;
 };
 
-typedef struct item
-{
- struct hashhdr hdr;
-} ITEM ;
-
-# define MAX_LISTS 32
+#define MAX_LISTS 32
 
 struct hash
 {
     /*
      * the hash table, just an array of item pointers
      */
- struct {
+ struct
+ {
         int nel;
- ITEM **base;
+ ITEM * * base;
     } tab;
 
     int bloat; /* tab.nel / items.nel */
     int inel; /* initial number of elements */
 
     /*
- * the array of records, maintained by these routines
- * essentially a microallocator
+ * the array of records, maintained by these routines - essentially a
+ * microallocator
      */
- struct {
- int more; /* how many more ITEMs fit in lists[ list ] */
- ITEM *free; /* free list of items */
- char *next; /* where to put more ITEMs in lists[ list ] */
- int size; /* sizeof( ITEM ) + aligned datalen */
- int nel; /* total ITEMs held by all lists[] */
- int list; /* index into lists[] */
-
- struct {
- int nel; /* total ITEMs held by this list */
- char *base; /* base of ITEMs array */
+ struct
+ {
+ int more; /* how many more ITEMs fit in lists[ list ] */
+ ITEM * free; /* free list of items */
+ char * next; /* where to put more ITEMs in lists[ list ] */
+ int size; /* sizeof( ITEM ) + aligned datalen */
+ int nel; /* total ITEMs held by all lists[] */
+ int list; /* index into lists[] */
+
+ struct
+ {
+ int nel; /* total ITEMs held by this list */
+ char * base; /* base of ITEMs array */
         } lists[ MAX_LISTS ];
     } items;
 
- const char * name; /* just for hashstats() */
+ char const * name; /* just for hashstats() */
 };
 
-static void hashrehash( struct hash *hp );
-static void hashstat( struct hash *hp );
+static void hashrehash( struct hash * );
+static void hashstat( struct hash * );
 
 static unsigned int hash_keyval( OBJECT * key )
 {
     return object_hash( key );
 }
 
-#define hash_bucket(hp,keyval) ((hp)->tab.base + ( (keyval) % (hp)->tab.nel ))
+#define hash_bucket(hp, keyval) ((hp)->tab.base + ((keyval) % (hp)->tab.nel))
 
 #define hash_data_key(data) (*(OBJECT * *)(data))
-#define hash_item_data(item) ((HASHDATA *)((char *)item + sizeof(struct hashhdr)))
+#define hash_item_data(item) ((HASHDATA *)((char *)item + sizeof(ITEM)))
 #define hash_item_key(item) (hash_data_key(hash_item_data(item)))
 
-/* Find the hash item for the given data. Returns pointer to the
- item and if given a pointer to the item before the found item.
- If it's the first item in a bucket, there is no previous item,
- and zero is returned for the previous item instead.
-*/
-static ITEM * hash_search(
- struct hash *hp,
- unsigned int keyval,
- OBJECT * keydata,
- ITEM * * previous )
+
+#define ALIGNED(x) ((x + sizeof(ITEM) - 1) & ~(sizeof(ITEM) - 1))
+
+/*
+ * hashinit() - initialize a hash table, returning a handle
+ */
+
+struct hash * hashinit( int datalen, char const * name )
 {
- ITEM * i = *hash_bucket(hp,keyval);
- ITEM * p = 0;
+ struct hash * hp = (struct hash *)BJAM_MALLOC( sizeof( *hp ) );
 
- for ( ; i; i = i->hdr.next )
+ hp->bloat = 3;
+ hp->tab.nel = 0;
+ hp->tab.base = 0;
+ hp->items.more = 0;
+ hp->items.free = 0;
+ hp->items.size = sizeof( ITEM ) + ALIGNED( datalen );
+ hp->items.list = -1;
+ hp->items.nel = 0;
+ hp->inel = 11; /* 47 */
+ hp->name = name;
+
+ return hp;
+}
+
+
+/*
+ * hash_search() - Find the hash item for the given data.
+ *
+ * Returns a pointer to a hashed item with the given key. If given a 'previous'
+ * pointer, makes it point to the item prior to the found item in the same
+ * bucket or to 0 if our item is the first item in its bucket.
+ */
+
+static ITEM * hash_search( struct hash * hp, unsigned int keyval,
+ OBJECT * keydata, ITEM * * previous )
+{
+ ITEM * i = *hash_bucket( hp, keyval );
+ ITEM * p = 0;
+ for ( ; i; i = i->next )
     {
         if ( object_equal( hash_item_key( i ), keydata ) )
         {
- if (previous)
- {
+ if ( previous )
                 *previous = p;
- }
             return i;
         }
         p = i;
     }
-
     return 0;
 }
 
+
 /*
  * hash_insert() - insert a record in the table or return the existing one
  */
@@ -132,7 +151,7 @@
     unsigned int keyval = hash_keyval( key );
 
     #ifdef HASH_DEBUG_PROFILE
- profile_frame prof[1];
+ profile_frame prof[ 1 ];
     if ( DEBUG_PROFILE )
         profile_enter( 0, prof );
     #endif
@@ -142,27 +161,25 @@
 
     i = hash_search( hp, keyval, key, 0 );
     if ( i )
- {
         *found = 1;
- }
     else
     {
         ITEM * * base = hash_bucket( hp, keyval );
 
- /* try to grab one from the free list */
+ /* Try to grab one from the free list. */
         if ( hp->items.free )
         {
             i = hp->items.free;
- hp->items.free = i->hdr.next;
- assert( hash_item_key( i ) == 0 );
+ hp->items.free = i->next;
+ assert( !hash_item_key( i ) );
         }
         else
         {
             i = (ITEM *)hp->items.next;
             hp->items.next += hp->items.size;
         }
- hp->items.more--;
- i->hdr.next = *base;
+ --hp->items.more;
+ i->next = *base;
         *base = i;
         *found = 0;
     }
@@ -175,17 +192,18 @@
     return hash_item_data( i );
 }
 
+
 /*
  * hash_find() - find a record in the table or NULL if none exists
  */
 
-HASHDATA * hash_find( struct hash *hp, OBJECT *key )
+HASHDATA * hash_find( struct hash * hp, OBJECT * key )
 {
- ITEM *i;
- unsigned int keyval = hash_keyval(key);
+ ITEM * i;
+ unsigned int keyval = hash_keyval( key );
 
     #ifdef HASH_DEBUG_PROFILE
- profile_frame prof[1];
+ profile_frame prof[ 1 ];
     if ( DEBUG_PROFILE )
         profile_enter( 0, prof );
     #endif
@@ -206,136 +224,93 @@
         profile_exit( prof );
     #endif
 
- if (i)
- {
- return hash_item_data( i );
- }
- else
- {
- return 0;
- }
+ return i ? hash_item_data( i ) : 0;
 }
 
+
 /*
  * hashrehash() - resize and rebuild hp->tab, the hash table
  */
 
-static void hashrehash( register struct hash *hp )
+static void hashrehash( struct hash * hp )
 {
     int i = ++hp->items.list;
     hp->items.more = i ? 2 * hp->items.nel : hp->inel;
     hp->items.next = (char *)BJAM_MALLOC( hp->items.more * hp->items.size );
     hp->items.free = 0;
 
- hp->items.lists[i].nel = hp->items.more;
- hp->items.lists[i].base = hp->items.next;
+ hp->items.lists[ i ].nel = hp->items.more;
+ hp->items.lists[ i ].base = hp->items.next;
     hp->items.nel += hp->items.more;
 
     if ( hp->tab.base )
         BJAM_FREE( (char *)hp->tab.base );
 
     hp->tab.nel = hp->items.nel * hp->bloat;
- hp->tab.base = (ITEM **)BJAM_MALLOC( hp->tab.nel * sizeof(ITEM **) );
+ hp->tab.base = (ITEM * *)BJAM_MALLOC( hp->tab.nel * sizeof( ITEM * * ) );
 
     memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
 
     for ( i = 0; i < hp->items.list; ++i )
     {
- int nel = hp->items.lists[i].nel;
- char *next = hp->items.lists[i].base;
+ int nel = hp->items.lists[ i ].nel;
+ char * next = hp->items.lists[ i ].base;
 
         for ( ; nel--; next += hp->items.size )
         {
- register ITEM *i = (ITEM *)next;
- ITEM **ip = hp->tab.base + object_hash( hash_item_key( i ) ) % hp->tab.nel;
- /* code currently assumes rehashing only when there are no free items */
- assert( hash_item_key( i ) != 0 );
+ ITEM * i = (ITEM *)next;
+ ITEM * * ip = hp->tab.base + object_hash( hash_item_key( i ) ) %
+ hp->tab.nel;
+ /* code currently assumes rehashing only when there are no free
+ * items
+ */
+ assert( hash_item_key( i ) );
 
- i->hdr.next = *ip;
+ i->next = *ip;
             *ip = i;
         }
     }
 }
 
-void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data )
+
+void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
+ )
 {
     int i;
     for ( i = 0; i <= hp->items.list; ++i )
     {
- char * next = hp->items.lists[i].base;
- int nel = hp->items.lists[i].nel;
+ char * next = hp->items.lists[ i ].base;
+ int nel = hp->items.lists[ i ].nel;
         if ( i == hp->items.list )
             nel -= hp->items.more;
 
         for ( ; nel--; next += hp->items.size )
         {
- ITEM * i = (ITEM *)next;
- if ( hash_item_key( i ) != 0 ) /* DO not enumerate freed items. */
+ ITEM * const i = (ITEM *)next;
+ if ( hash_item_key( i ) != 0 ) /* Do not enumerate freed items. */
                 f( hash_item_data( i ), data );
         }
     }
 }
 
-/* --- */
-
-# define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
-
-/*
- * hashinit() - initialize a hash table, returning a handle
- */
-
-struct hash *
-hashinit(
- int datalen,
- const char *name )
-{
- struct hash *hp = (struct hash *)BJAM_MALLOC( sizeof( *hp ) );
-
- hp->bloat = 3;
- hp->tab.nel = 0;
- hp->tab.base = (ITEM **)0;
- hp->items.more = 0;
- hp->items.free = 0;
- hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
- hp->items.list = -1;
- hp->items.nel = 0;
- hp->inel = 11 /* 47 */;
- hp->name = name;
-
- return hp;
-}
-
-void hashdone( struct hash * hp )
-{
- if ( !hp )
- return;
- if ( DEBUG_MEM || DEBUG_PROFILE )
- hashstat( hp );
- hash_free( hp );
-}
 
 /*
  * hash_free() - free a hash table, given its handle
  */
 
-void
-hash_free( struct hash * hp )
+void hash_free( struct hash * hp )
 {
     int i;
-
     if ( !hp )
         return;
-
     if ( hp->tab.base )
         BJAM_FREE( (char *)hp->tab.base );
     for ( i = 0; i <= hp->items.list; ++i )
- BJAM_FREE( hp->items.lists[i].base );
+ BJAM_FREE( hp->items.lists[ i ].base );
     BJAM_FREE( (char *)hp );
 }
 
 
-/* ---- */
-
 static void hashstat( struct hash * hp )
 {
     struct hashstats stats[ 1 ];
@@ -344,6 +319,7 @@
     hashstats_print( stats, hp->name );
 }
 
+
 void hashstats_init( struct hashstats * stats )
 {
     stats->count = 0;
@@ -351,8 +327,10 @@
     stats->tab_size = 0;
     stats->item_size = 0;
     stats->sets = 0;
+ stats->num_hashes = 0;
 }
 
+
 void hashstats_add( struct hashstats * stats, struct hash * hp )
 {
     if ( hp )
@@ -367,7 +345,7 @@
         {
             ITEM * item;
             int here = 0;
- for ( item = tab[ i ]; item != 0; item = item->hdr.next )
+ for ( item = tab[ i ]; item; item = item->next )
                 ++here;
 
             count += here;
@@ -380,17 +358,30 @@
         stats->num_items += hp->items.nel;
         stats->tab_size += hp->tab.nel;
         stats->item_size = hp->items.size;
+ ++stats->num_hashes;
     }
 }
 
-void hashstats_print( struct hashstats * stats, const char * name )
+
+void hashstats_print( struct hashstats * stats, char const * name )
 {
- printf( "%s table: %d+%d+%d (%dK+%luK) items+table+hash, %f density\n",
+ printf( "%s table: %d+%d+%d (%dK+%luK+%luK) items+table+hash, %f density\n",
         name,
         stats->count,
         stats->num_items,
         stats->tab_size,
         stats->num_items * stats->item_size / 1024,
- (long unsigned)stats->tab_size * sizeof( ITEM ** ) / 1024,
+ (long unsigned)stats->tab_size * sizeof( ITEM * * ) / 1024,
+ (long unsigned)stats->num_hashes * sizeof( struct hash ) / 1024,
         (float)stats->count / (float)stats->sets );
 }
+
+
+void hashdone( struct hash * hp )
+{
+ if ( !hp )
+ return;
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ hashstat( hp );
+ hash_free( hp );
+}

Modified: branches/release/tools/build/v2/engine/hash.h
==============================================================================
--- branches/release/tools/build/v2/engine/hash.h (original)
+++ branches/release/tools/build/v2/engine/hash.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,57 +11,57 @@
 #ifndef BOOST_JAM_HASH_H
 #define BOOST_JAM_HASH_H
 
+#include "object.h"
+
 /*
- * An opaque struct representing an item in the
- * hash table. The first element of every struct
- * stored in the table must be an OBJECT * which
- * is treated as the key.
+ * An opaque struct representing an item in the hash table. The first element of
+ * every struct stored in the table must be an OBJECT * which is treated as the
+ * key.
  */
 typedef struct hashdata HASHDATA;
 
 /*
  * hashinit() - initialize a hash table, returning a handle.
- * datalen is the size of the items. name is used for debugging.
+ *
+ * Parameters:
+ * datalen - item size
+ * name - used for debugging
  */
-struct hash * hashinit ( int datalen, const char * name );
+struct hash * hashinit( int datalen, char const * name );
 
 /*
  * hash_free() - free a hash table, given its handle
  */
-void hash_free( struct hash * hp );
-void hashdone( struct hash * hp );
+void hash_free( struct hash * );
+void hashdone( struct hash * );
 
 /*
- * hashenumerate() - call f(i, data) on each item, i in the hash
- * table. The order of the items is unspecified.
+ * hashenumerate() - call f(i, data) on each item, i in the hash table. The
+ * enumeration order is unspecified.
  */
-void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data );
+void hashenumerate( struct hash *, void (* f)( void *, void * ), void * data );
 
 /*
- * hash_insert() - insert a new item in a hash table, or return an
- * existing one.
+ * hash_insert() - insert a new item in a hash table, or return an existing one.
  *
  * Preconditions:
- * - hp must be a hash table created by hashinit
- * - key must be an object created by object_new
+ * - hp must be a hash table created by hashinit()
+ * - key must be an object created by object_new()
  *
  * Postconditions:
- * - if the key does not already exist in the hash
- * table, *found == 0 and the result will be a
- * pointer to an uninitialized item. The key
- * of the new item must be set to a value equal to
- * key before any further operations on the
- * hash table except hashdone.
- * - if the key is present then *found == 1 and
- * the result is a pointer to the existing
- * record.
+ * - if the key does not already exist in the hash table, *found == 0 and the
+ * result will be a pointer to an uninitialized item. The key of the new
+ * item must be set to a value equal to key before any further operations on
+ * the hash table except hashdone().
+ * - if the key is present then *found == 1 and the result is a pointer to the
+ * existing record.
  */
-HASHDATA * hash_insert ( struct hash * hp, OBJECT * key, int * found );
+HASHDATA * hash_insert( struct hash *, OBJECT * key, int * found );
 
 /*
  * hash_find() - find a record in the table or NULL if none exists
  */
-HASHDATA * hash_find ( struct hash * hp, OBJECT * key );
+HASHDATA * hash_find( struct hash *, OBJECT * key );
 
 struct hashstats {
     int count;
@@ -69,10 +69,11 @@
     int tab_size;
     int item_size;
     int sets;
+ int num_hashes;
 };
 
 void hashstats_init( struct hashstats * stats );
-void hashstats_add( struct hashstats * stats, struct hash * hp );
-void hashstats_print( struct hashstats * stats, const char * name );
+void hashstats_add( struct hashstats * stats, struct hash * );
+void hashstats_print( struct hashstats * stats, char const * name );
 
 #endif

Modified: branches/release/tools/build/v2/engine/hcache.c
==============================================================================
--- branches/release/tools/build/v2/engine/hcache.c (original)
+++ branches/release/tools/build/v2/engine/hcache.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,21 +2,6 @@
  * This file has been donated to Jam.
  */
 
-# include "jam.h"
-# include "lists.h"
-# include "parse.h"
-# include "rules.h"
-# include "regexp.h"
-# include "headers.h"
-# include "object.h"
-# include "hash.h"
-# include "hcache.h"
-# include "variable.h"
-# include "search.h"
-# include "modules.h"
-
-#ifdef OPT_HEADER_CACHE_EXT
-
 /*
  * Craig W. McPheeters, Alias|Wavefront.
  *
@@ -28,7 +13,7 @@
  * files found in their scan. During the binding phase of jam, look in the
  * header cache first for the headers contained in a file. If the cache is
  * present and valid, use its contents. This results in dramatic speedups with
- * large projects (eg. 3min -> 1min startup for one project.)
+ * large projects (e.g. 3min -> 1min startup for one project.)
  *
  * External routines:
  * hcache_init() - read and parse the local .jamdeps file.
@@ -37,29 +22,46 @@
  *
  * The dependency file format is an ASCII file with 1 line per target. Each line
  * has the following fields:
- * @boundname@ timestamp @file@ @file@ @file@ ... \n
+ * @boundname@ timestamp_sec timestamp_nsec @file@ @file@ @file@ ...
  */
 
+#ifdef OPT_HEADER_CACHE_EXT
+
+#include "jam.h"
+#include "hcache.h"
+
+#include "hash.h"
+#include "headers.h"
+#include "lists.h"
+#include "modules.h"
+#include "object.h"
+#include "parse.h"
+#include "regexp.h"
+#include "rules.h"
+#include "search.h"
+#include "timestamp.h"
+#include "variable.h"
+
 typedef struct hcachedata HCACHEDATA ;
 
 struct hcachedata
 {
     OBJECT * boundname;
- time_t time;
+ timestamp time;
     LIST * includes;
     LIST * hdrscan; /* the HDRSCAN value for this target */
- int age; /* if too old, we'll remove it from cache */
+ int age; /* if too old, we will remove it from cache */
     HCACHEDATA * next;
 };
 
 
 static struct hash * hcachehash = 0;
-static HCACHEDATA * hcachelist = 0;
+static HCACHEDATA * hcachelist = 0;
 
 static int queries = 0;
 static int hits = 0;
 
-#define CACHE_FILE_VERSION "version 4"
+#define CACHE_FILE_VERSION "version 5"
 #define CACHE_RECORD_HEADER "header"
 #define CACHE_RECORD_END "end"
 
@@ -76,11 +78,11 @@
     static OBJECT * name = 0;
     if ( !name )
     {
- LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );
+ LIST * const hcachevar = var_get( root_module(), constant_HCACHEFILE );
 
         if ( !list_empty( hcachevar ) )
         {
- TARGET * t = bindtarget( list_front( hcachevar ) );
+ TARGET * const t = bindtarget( list_front( hcachevar ) );
 
             pushsettings( root_module(), t->settings );
             /* Do not expect the cache file to be generated, so pass 0 as the
@@ -99,14 +101,14 @@
 
 
 /*
- * Return the maximum age a cache entry can have before it is purged ftom the
+ * Return the maximum age a cache entry can have before it is purged from the
  * cache.
  */
 
 static int cache_maxage( void )
 {
     int age = 100;
- LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
+ LIST * const var = var_get( root_module(), constant_HCACHEMAXAGE );
     if ( !list_empty( var ) )
     {
         age = atoi( object_str( list_front( var ) ) );
@@ -199,7 +201,8 @@
         HCACHEDATA cachedata;
         HCACHEDATA * c;
         OBJECT * record_type = 0;
- OBJECT * time_str = 0;
+ OBJECT * time_secs_str = 0;
+ OBJECT * time_nsecs_str = 0;
         OBJECT * age_str = 0;
         OBJECT * includes_count_str = 0;
         OBJECT * hdrscan_count_str = 0;
@@ -231,23 +234,26 @@
         }
 
         cachedata.boundname = read_netstring( f );
- time_str = read_netstring( f );
+ time_secs_str = read_netstring( f );
+ time_nsecs_str = read_netstring( f );
         age_str = read_netstring( f );
         includes_count_str = read_netstring( f );
 
- if ( !cachedata.boundname || !time_str || !age_str || !includes_count_str )
+ if ( !cachedata.boundname || !time_secs_str || !time_nsecs_str ||
+ !age_str || !includes_count_str )
         {
             fprintf( stderr, "invalid %s\n", hcachename );
             goto cleanup;
         }
 
- cachedata.time = atoi( object_str( time_str ) );
+ timestamp_init( &cachedata.time, atoi( object_str( time_secs_str ) ),
+ atoi( object_str( time_nsecs_str ) ) );
         cachedata.age = atoi( object_str( age_str ) ) + 1;
 
         count = atoi( object_str( includes_count_str ) );
         for ( l = L0, i = 0; i < count; ++i )
         {
- OBJECT * s = read_netstring( f );
+ OBJECT * const s = read_netstring( f );
             if ( !s )
             {
                 fprintf( stderr, "invalid %s\n", hcachename );
@@ -268,7 +274,7 @@
         count = atoi( object_str( hdrscan_count_str ) );
         for ( l = L0, i = 0; i < count; ++i )
         {
- OBJECT * s = read_netstring( f );
+ OBJECT * const s = read_netstring( f );
             if ( !s )
             {
                 fprintf( stderr, "invalid %s\n", hcachename );
@@ -279,19 +285,20 @@
         }
         cachedata.hdrscan = l;
 
- c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found );
+ c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found )
+ ;
         if ( !found )
         {
             c->boundname = cachedata.boundname;
- c->time = cachedata.time;
             c->includes = cachedata.includes;
             c->hdrscan = cachedata.hdrscan;
             c->age = cachedata.age;
+ timestamp_copy( &c->time, &cachedata.time );
         }
         else
         {
- fprintf( stderr, "can't insert header cache item, bailing on %s\n",
- hcachename );
+ fprintf( stderr, "can not insert header cache item, bailing on %s"
+ "\n", hcachename );
             goto cleanup;
         }
 
@@ -299,9 +306,10 @@
         hcachelist = c;
 
         ++header_count;
-
+
         object_free( record_type );
- object_free( time_str );
+ object_free( time_secs_str );
+ object_free( time_nsecs_str );
         object_free( age_str );
         object_free( includes_count_str );
         object_free( hdrscan_count_str );
@@ -310,7 +318,8 @@
 cleanup:
 
         if ( record_type ) object_free( record_type );
- if ( time_str ) object_free( time_str );
+ if ( time_secs_str ) object_free( time_secs_str );
+ if ( time_nsecs_str ) object_free( time_nsecs_str );
         if ( age_str ) object_free( age_str );
         if ( includes_count_str ) object_free( includes_count_str );
         if ( hdrscan_count_str ) object_free( hdrscan_count_str );
@@ -357,25 +366,31 @@
     c = hcachelist;
     for ( c = hcachelist; c; c = c->next )
     {
- LISTITER iter, end;
- char time_str[ 30 ];
- char age_str[ 30 ];
- char includes_count_str[ 30 ];
- char hdrscan_count_str[ 30 ];
+ LISTITER iter;
+ LISTITER end;
+ char time_secs_str[ 30 ];
+ char time_nsecs_str[ 30 ];
+ char age_str[ 30 ];
+ char includes_count_str[ 30 ];
+ char hdrscan_count_str[ 30 ];
 
         if ( maxage == 0 )
             c->age = 0;
         else if ( c->age > maxage )
             continue;
 
- sprintf( includes_count_str, "%lu", (long unsigned) list_length( c->includes ) );
- sprintf( hdrscan_count_str, "%lu", (long unsigned) list_length( c->hdrscan ) );
- sprintf( time_str, "%lu", (long unsigned) c->time );
- sprintf( age_str, "%lu", (long unsigned) c->age );
+ sprintf( includes_count_str, "%lu", (long unsigned)list_length(
+ c->includes ) );
+ sprintf( hdrscan_count_str, "%lu", (long unsigned)list_length(
+ c->hdrscan ) );
+ sprintf( time_secs_str, "%lu", (long unsigned)c->time.secs );
+ sprintf( time_nsecs_str, "%lu", (long unsigned)c->time.nsecs );
+ sprintf( age_str, "%lu", (long unsigned)c->age );
 
         write_netstring( f, CACHE_RECORD_HEADER );
         write_netstring( f, object_str( c->boundname ) );
- write_netstring( f, time_str );
+ write_netstring( f, time_secs_str );
+ write_netstring( f, time_nsecs_str );
         write_netstring( f, age_str );
         write_netstring( f, includes_count_str );
         for ( iter = list_begin( c->includes ), end = list_end( c->includes );
@@ -395,7 +410,7 @@
             hcachename, header_count, queries ? 100.0 * hits / queries : 0 );
 
     fclose ( f );
-
+
 cleanup:
     for ( c = hcachelist; c; c = c->next )
     {
@@ -415,23 +430,22 @@
 {
     HCACHEDATA * c;
 
- LIST * l = 0;
-
     ++queries;
 
     if ( ( c = (HCACHEDATA *)hash_find( hcachehash, t->boundname ) ) )
     {
- if ( c->time == t->time )
+ if ( !timestamp_cmp( &c->time, &t->time ) )
         {
- LIST *l1 = hdrscan, *l2 = c->hdrscan;
- LISTITER iter1 = list_begin( l1 ), end1 = list_end( l1 ),
- iter2 = list_begin( l2 ), end2 = list_end( l2 );
+ LIST * const l1 = hdrscan;
+ LIST * const l2 = c->hdrscan;
+ LISTITER iter1 = list_begin( l1 );
+ LISTITER const end1 = list_end( l1 );
+ LISTITER iter2 = list_begin( l2 );
+ LISTITER const end2 = list_end( l2 );
             while ( iter1 != end1 && iter2 != end2 )
             {
                 if ( !object_equal( list_item( iter1 ), list_item( iter2 ) ) )
- {
                     iter1 = end1;
- }
                 else
                 {
                     iter1 = list_next( iter1 );
@@ -440,17 +454,16 @@
             }
             if ( iter1 != end1 || iter2 != end2 )
             {
- if (DEBUG_HEADER)
+ if ( DEBUG_HEADER )
+ {
                     printf( "HDRSCAN out of date in cache for %s\n",
                         object_str( t->boundname ) );
-
- printf( "HDRSCAN out of date for %s\n",
- object_str( t->boundname ) );
- printf(" real : ");
- list_print( hdrscan );
- printf( "\n cached: " );
- list_print( c->hdrscan );
- printf( "\n" );
+ printf(" real : ");
+ list_print( hdrscan );
+ printf( "\n cached: " );
+ list_print( c->hdrscan );
+ printf( "\n" );
+ }
 
                 list_free( c->includes );
                 list_free( c->hdrscan );
@@ -459,20 +472,19 @@
             }
             else
             {
- if (DEBUG_HEADER)
- printf( "using header cache for %s\n",
- object_str( t->boundname ) );
+ if ( DEBUG_HEADER )
+ printf( "using header cache for %s\n", object_str(
+ t->boundname ) );
                 c->age = 0;
                 ++hits;
- l = list_copy( c->includes );
- return l;
+ return list_copy( c->includes );
             }
         }
         else
         {
- if (DEBUG_HEADER)
- printf ("header cache out of date for %s\n",
- object_str( t->boundname ) );
+ if ( DEBUG_HEADER )
+ printf ("header cache out of date for %s\n", object_str(
+ t->boundname ) );
             list_free( c->includes );
             list_free( c->hdrscan );
             c->includes = L0;
@@ -492,15 +504,16 @@
     }
 
     /* 'c' points at the cache entry. Its out of date. */
+ {
+ LIST * const l = headers1( L0, t->boundname, rec, re );
 
- l = headers1( L0, t->boundname, rec, re );
-
- c->time = t->time;
- c->age = 0;
- c->includes = list_copy( l );
- c->hdrscan = list_copy( hdrscan );
+ timestamp_copy( &c->time, &t->time );
+ c->age = 0;
+ c->includes = list_copy( l );
+ c->hdrscan = list_copy( hdrscan );
 
- return l;
+ return l;
+ }
 }
 
-#endif
+#endif /* OPT_HEADER_CACHE_EXT */

Modified: branches/release/tools/build/v2/engine/hcache.h
==============================================================================
--- branches/release/tools/build/v2/engine/hcache.h (original)
+++ branches/release/tools/build/v2/engine/hcache.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,13 +6,14 @@
  * hcache.h - handle #includes in source files
  */
 #ifndef HCACHE_H
-# define HCACHE_H
+#define HCACHE_H
 
-# include "regexp.h"
-# include "lists.h"
+#include "lists.h"
+#include "regexp.h"
+#include "rules.h"
 
 void hcache_init( void );
 void hcache_done( void );
-LIST * hcache( TARGET *t, int rec, regexp * re[], LIST * hdrscan );
+LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan );
 
 #endif

Modified: branches/release/tools/build/v2/engine/hdrmacro.c
==============================================================================
--- branches/release/tools/build/v2/engine/hdrmacro.c (original)
+++ branches/release/tools/build/v2/engine/hdrmacro.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,42 +10,37 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-# include "jam.h"
-# include "lists.h"
-# include "parse.h"
-# include "compile.h"
-# include "rules.h"
-# include "variable.h"
-# include "regexp.h"
-# include "hdrmacro.h"
-# include "hash.h"
-# include "object.h"
-# include "strings.h"
-
 /*
- * hdrmacro.c - handle header files that define macros used in
- * #include statements.
- *
- * we look for lines like "#define MACRO <....>" or '#define MACRO " "'
- * in the target file. When found, we
+ * hdrmacro.c - handle header files that define macros used in #include
+ * statements.
  *
- * we then phony up a rule invocation like:
+ * we look for lines like "#define MACRO <....>" or '#define MACRO " "' in
+ * the target file. When found, we then phony up a rule invocation like:
  *
  * $(HDRRULE) <target> : <resolved included files> ;
  *
  * External routines:
- * headers1() - scan a target for "#include MACRO" lines and try
- * to resolve them when needed
+ * headers1() - scan a target for "#include MACRO" lines and try to resolve
+ * them when needed
  *
  * Internal routines:
  * headers1() - using regexp, scan a file and build include LIST
- *
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
- * so that headers() doesn't have to mock up a parse structure
- * just to invoke a rule.
  */
 
+#include "jam.h"
+#include "hdrmacro.h"
+
+#include "compile.h"
+#include "hash.h"
+#include "lists.h"
+#include "object.h"
+#include "parse.h"
+#include "rules.h"
+#include "strings.h"
+#include "subst.h"
+#include "variable.h"
+
+
 /* this type is used to store a dictionary of file header macros */
 typedef struct header_macro
 {
@@ -60,24 +55,24 @@
  * headers() - scan a target for include files and call HDRRULE
  */
 
-# define MAXINC 10
+#define MAXINC 10
 
-void
-macro_headers( TARGET * t )
+void macro_headers( TARGET * t )
 {
- static regexp *re = 0;
- FILE *f;
- char buf[ 1024 ];
+ static regexp * re = 0;
+ FILE * f;
+ char buf[ 1024 ];
 
     if ( DEBUG_HEADER )
         printf( "macro header scan for %s\n", object_str( t->name ) );
 
- /* this regexp is used to detect lines of the form */
- /* "#define MACRO <....>" or "#define MACRO "....." */
- /* in the header macro files.. */
- if ( re == 0 )
+ /* This regexp is used to detect lines of the form
+ * "#define MACRO <....>" or "#define MACRO "....."
+ * in the header macro files.
+ */
+ if ( !re )
     {
- OBJECT * re_str = object_new(
+ OBJECT * const re_str = object_new(
             "^[ ]*#[ ]*define[ ]*([A-Za-z][A-Za-z0-9_]*)[ ]*"
             "[<\"]([^\">]*)[\">].*$" );
         re = regex_compile( re_str );
@@ -90,35 +85,36 @@
     while ( fgets( buf, sizeof( buf ), f ) )
     {
         HEADER_MACRO var;
- HEADER_MACRO *v = &var;
+ HEADER_MACRO * v = &var;
 
- if ( regexec( re, buf ) && re->startp[1] )
+ if ( regexec( re, buf ) && re->startp[ 1 ] )
         {
             OBJECT * symbol;
             int found;
             /* we detected a line that looks like "#define MACRO filename */
- ((char *)re->endp[1])[0] = '\0';
- ((char *)re->endp[2])[0] = '\0';
+ ( (char *)re->endp[ 1 ] )[ 0 ] = '\0';
+ ( (char *)re->endp[ 2 ] )[ 0 ] = '\0';
 
             if ( DEBUG_HEADER )
                 printf( "macro '%s' used to define filename '%s' in '%s'\n",
- re->startp[1], re->startp[2], object_str( t->boundname ) );
+ re->startp[ 1 ], re->startp[ 2 ], object_str( t->boundname )
+ );
 
             /* add macro definition to hash table */
             if ( !header_macros_hash )
- header_macros_hash = hashinit( sizeof( HEADER_MACRO ), "hdrmacros" );
+ header_macros_hash = hashinit( sizeof( HEADER_MACRO ),
+ "hdrmacros" );
 
- symbol = object_new( re->startp[1] );
- v = (HEADER_MACRO *)hash_insert( header_macros_hash, symbol, &found );
+ symbol = object_new( re->startp[ 1 ] );
+ v = (HEADER_MACRO *)hash_insert( header_macros_hash, symbol, &found
+ );
             if ( !found )
             {
                 v->symbol = symbol;
- v->filename = object_new( re->startp[2] ); /* never freed */
+ v->filename = object_new( re->startp[ 2 ] ); /* never freed */
             }
             else
- {
                 object_free( symbol );
- }
             /* XXXX: FOR NOW, WE IGNORE MULTIPLE MACRO DEFINITIONS !! */
             /* WE MIGHT AS WELL USE A LIST TO STORE THEM.. */
         }
@@ -131,11 +127,12 @@
 OBJECT * macro_header_get( OBJECT * macro_name )
 {
     HEADER_MACRO * v;
-
- if ( header_macros_hash && ( v = (HEADER_MACRO *)hash_find( header_macros_hash, macro_name ) ) )
+ if ( header_macros_hash && ( v = (HEADER_MACRO *)hash_find(
+ header_macros_hash, macro_name ) ) )
     {
         if ( DEBUG_HEADER )
- printf( "### macro '%s' evaluated to '%s'\n", object_str( macro_name ), object_str( v->filename ) );
+ printf( "### macro '%s' evaluated to '%s'\n", object_str( macro_name
+ ), object_str( v->filename ) );
         return v->filename;
     }
     return 0;

Modified: branches/release/tools/build/v2/engine/hdrmacro.h
==============================================================================
--- branches/release/tools/build/v2/engine/hdrmacro.h (original)
+++ branches/release/tools/build/v2/engine/hdrmacro.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,8 +12,10 @@
 #ifndef HDRMACRO_SW20111118_H
 #define HDRMACRO_SW20111118_H
 
-void macro_headers( TARGET *t );
+#include "object.h"
+#include "rules.h"
 
-OBJECT * macro_header_get( OBJECT * macro_name );
+void macro_headers( TARGET * );
+OBJECT * macro_header_get( OBJECT * macro_name );
 
 #endif

Modified: branches/release/tools/build/v2/engine/headers.c
==============================================================================
--- branches/release/tools/build/v2/engine/headers.c (original)
+++ branches/release/tools/build/v2/engine/headers.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,64 +9,59 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-# include "jam.h"
-# include "lists.h"
-# include "parse.h"
-# include "compile.h"
-# include "rules.h"
-# include "modules.h"
-# include "variable.h"
-# include "regexp.h"
-# include "headers.h"
-# include "hdrmacro.h"
-# include "object.h"
-
-#ifdef OPT_HEADER_CACHE_EXT
-# include "hcache.h"
-#endif
-
 /*
  * headers.c - handle #includes in source files
  *
- * Using regular expressions provided as the variable $(HDRSCAN),
- * headers() searches a file for #include files and phonies up a
- * rule invocation:
- *
- * $(HDRRULE) <target> : <include files> ;
+ * Using regular expressions provided as the variable $(HDRSCAN), headers()
+ * searches a file for #include files and phonies up a rule invocation:
+ * $(HDRRULE) <target> : <include files> ;
  *
  * External routines:
  * headers() - scan a target for include files and call HDRRULE
  *
  * Internal routines:
  * headers1() - using regexp, scan a file and build include LIST
- *
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 09/10/00 (seiwald) - replaced call to compile_rule with evaluate_rule,
- * so that headers() doesn't have to mock up a parse structure
- * just to invoke a rule.
  */
 
+#include "jam.h"
+#include "headers.h"
+
+#include "compile.h"
+#include "hdrmacro.h"
+#include "lists.h"
+#include "modules.h"
+#include "object.h"
+#include "parse.h"
+#include "rules.h"
+#include "subst.h"
+#include "variable.h"
+
+#ifdef OPT_HEADER_CACHE_EXT
+# include "hcache.h"
+#endif
+
 #ifndef OPT_HEADER_CACHE_EXT
-static LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[]);
+static LIST * headers1( LIST *, OBJECT * file, int rec, regexp * re[] );
 #endif
 
+
 /*
  * headers() - scan a target for include files and call HDRRULE
  */
 
-# define MAXINC 10
+#define MAXINC 10
 
-void
-headers( TARGET * t )
+void headers( TARGET * t )
 {
     LIST * hdrscan;
     LIST * hdrrule;
- #ifndef OPT_HEADER_CACHE_EXT
+ #ifndef OPT_HEADER_CACHE_EXT
     LIST * headlist = L0;
- #endif
+ #endif
     regexp * re[ MAXINC ];
     int rec = 0;
- LISTITER iter, end;
+ LISTITER iter;
+ LISTITER end;
 
     hdrscan = var_get( root_module(), constant_HDRSCAN );
     if ( list_empty( hdrscan ) )
@@ -80,7 +75,8 @@
         printf( "header scan %s\n", object_str( t->name ) );
 
     /* Compile all regular expressions in HDRSCAN */
- iter = list_begin( hdrscan ), end = list_end( hdrscan );
+ iter = list_begin( hdrscan );
+ end = list_end( hdrscan );
     for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
     {
         re[ rec++ ] = regex_compile( list_item( iter ) );
@@ -89,7 +85,7 @@
     /* Doctor up call to HDRRULE rule */
     /* Call headers1() to get LIST of included files. */
     {
- FRAME frame[1];
+ FRAME frame[ 1 ];
         frame_init( frame );
         lol_add( frame->args, list_new( object_copy( t->name ) ) );
 #ifdef OPT_HEADER_CACHE_EXT
@@ -100,11 +96,10 @@
 
         if ( lol_get( frame->args, 1 ) )
         {
- /* The third argument to HDRRULE is the bound name of
- * $(<) */
+ OBJECT * rulename = list_front( hdrrule );
+ /* The third argument to HDRRULE is the bound name of $(<). */
             lol_add( frame->args, list_new( object_copy( t->boundname ) ) );
-
- list_free( evaluate_rule( list_front( hdrrule ), frame ) );
+ list_free( evaluate_rule( bindrule( rulename, frame->module ), rulename, frame ) );
         }
 
         /* Clean up. */
@@ -117,35 +112,33 @@
  * headers1() - using regexp, scan a file and build include LIST.
  */
 
-#ifdef OPT_HEADER_CACHE_EXT
-LIST *
-#else
-static LIST *
+#ifndef OPT_HEADER_CACHE_EXT
+static
 #endif
-headers1(
- LIST * l,
- OBJECT * file,
- int rec,
- regexp * re[] )
+LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[] )
 {
     FILE * f;
     char buf[ 1024 ];
- int i;
+ int i;
     static regexp * re_macros = 0;
 
 #ifdef OPT_IMPROVED_PATIENCE_EXT
     static int count = 0;
     ++count;
- if ( ((count == 100) || !( count % 1000 )) && DEBUG_MAKE )
- printf("...patience...\n");
+ if ( ( ( count == 100 ) || !( count % 1000 ) ) && DEBUG_MAKE )
+ {
+ printf( "...patience...\n" );
+ fflush( stdout );
+ }
 #endif
 
- /* the following regexp is used to detect cases where a */
- /* file is included through a line line "#include MACRO" */
+ /* The following regexp is used to detect cases where a file is included
+ * through a line like "#include MACRO".
+ */
     if ( re_macros == 0 )
     {
- OBJECT * re_str = object_new(
- "^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" );
+ OBJECT * const re_str = object_new(
+ "#[ \t]*include[ \t]*([A-Za-z][A-Za-z0-9_]*).*$" );
         re_macros = regex_compile( re_str );
         object_free( re_str );
     }
@@ -155,45 +148,34 @@
 
     while ( fgets( buf, sizeof( buf ), f ) )
     {
- int size = strlen( buf );
- /* Remove trailing \r and \n, if any. */
- while ( ( size > 0 ) &&
- ( buf[ size - 1 ] == '\n' ) &&
- ( buf[ size - 1 ] == '\r' ) )
- {
- buf[ size - 1 ] = '\0';
- --size;
- }
-
         for ( i = 0; i < rec; ++i )
- if ( regexec( re[i], buf ) && re[i]->startp[1] )
+ if ( regexec( re[ i ], buf ) && re[ i ]->startp[ 1 ] )
             {
- ((char *)re[i]->endp[1])[0] = '\0';
-
+ ( (char *)re[ i ]->endp[ 1 ] )[ 0 ] = '\0';
                 if ( DEBUG_HEADER )
- printf( "header found: %s\n", re[i]->startp[1] );
-
- l = list_push_back( l, object_new( re[i]->startp[1] ) );
+ printf( "header found: %s\n", re[ i ]->startp[ 1 ] );
+ l = list_push_back( l, object_new( re[ i ]->startp[ 1 ] ) );
             }
 
- /* special treatment for #include MACRO */
- if ( regexec( re_macros, buf ) && re_macros->startp[1] )
+ /* Special treatment for #include MACRO. */
+ if ( regexec( re_macros, buf ) && re_macros->startp[ 1 ] )
         {
- OBJECT * header_filename;
+ OBJECT * header_filename;
             OBJECT * macro_name;
 
- ((char *)re_macros->endp[1])[0] = '\0';
+ ( (char *)re_macros->endp[ 1 ] )[ 0 ] = '\0';
 
             if ( DEBUG_HEADER )
- printf( "macro header found: %s", re_macros->startp[1] );
+ printf( "macro header found: %s", re_macros->startp[ 1 ] );
 
- macro_name = object_new( re_macros->startp[1] );
+ macro_name = object_new( re_macros->startp[ 1 ] );
             header_filename = macro_header_get( macro_name );
             object_free( macro_name );
             if ( header_filename )
             {
                 if ( DEBUG_HEADER )
- printf( " resolved to '%s'\n", object_str( header_filename ) );
+ printf( " resolved to '%s'\n", object_str( header_filename )
+ );
                 l = list_push_back( l, object_copy( header_filename ) );
             }
             else
@@ -205,12 +187,11 @@
     }
 
     fclose( f );
-
     return l;
 }
 
 
-void regerror( const char * s )
+void regerror( char const * s )
 {
     printf( "re error %s\n", s );
 }

Modified: branches/release/tools/build/v2/engine/jam.c
==============================================================================
--- branches/release/tools/build/v2/engine/jam.c (original)
+++ branches/release/tools/build/v2/engine/jam.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,17 +5,18 @@
  *
  * This file is part of jam.
  *
- * License is hereby granted to use this software and distribute it
- * freely, as long as this copyright notice is retained and modifications
- * are clearly marked.
+ * License is hereby granted to use this software and distribute it freely, as
+ * long as this copyright notice is retained and modifications are clearly
+ * marked.
  *
  * ALL WARRANTIES ARE HEREBY DISCLAIMED.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * 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)
  */
 
 /*
@@ -50,8 +51,8 @@
  * filesys
  *
  *
- * The support routines are called by all of the above, but themselves
- * are layered thus:
+ * The support routines are called by all of the above, but themselves are
+ * layered thus:
  *
  * variable|expand
  * / | |
@@ -72,8 +73,8 @@
  * builtins.c - jam's built-in rules
  * command.c - maintain lists of commands
  * compile.c - compile parsed jam statements
- * execunix.c - execute a shell script on UNIX
- * file*.c - scan directories and archives on *
+ * exec*.c - execute a shell script on a specific OS
+ * file*.c - scan directories and archives on a specific OS
  * hash.c - simple in-memory hashing routines
  * hdrmacro.c - handle header file parsing for filename macro definitions
  * headers.c - handle #includes in source files
@@ -85,7 +86,7 @@
  * object.c - string manipulation routines
  * option.c - command line option processing
  * parse.c - make and destroy parse trees as driven by the parser
- * path*.c - manipulate file names on *
+ * path*.c - manipulate file names on a specific OS
  * hash.c - simple in-memory hashing routines
  * regexp.c - Henry Spencer's regexp
  * rules.c - access to RULEs, TARGETs, and ACTIONs
@@ -93,50 +94,42 @@
  * search.c - find a target along $(SEARCH) or $(LOCATE)
  * timestamp.c - get the timestamp of a file or archive member
  * variable.c - handle jam multi-element variables
- *
- * 05/04/94 (seiwald) - async multiprocess (-j) support
- * 02/08/95 (seiwald) - -n implies -d2.
- * 02/22/95 (seiwald) - -v for version info.
- * 09/11/00 (seiwald) - PATCHLEVEL folded into VERSION.
- * 01/10/01 (seiwald) - pathsys.h split from filesys.h
  */
 
 
 #include "jam.h"
-#include "option.h"
 #include "patchlevel.h"
 
-/* These get various function declarations. */
-#include "lists.h"
-#include "parse.h"
-#include "variable.h"
-#include "compile.h"
 #include "builtins.h"
-#include "rules.h"
-#include "object.h"
-#include "scan.h"
-#include "timestamp.h"
-#include "make.h"
-#include "strings.h"
-#include "filesys.h"
-#include "output.h"
-#include "search.h"
 #include "class.h"
-#include "execcmd.h"
+#include "compile.h"
 #include "constants.h"
+#include "filesys.h"
 #include "function.h"
-#include "pwd.h"
 #include "hcache.h"
+#include "lists.h"
+#include "make.h"
+#include "object.h"
+#include "option.h"
+#include "output.h"
+#include "parse.h"
+#include "cwd.h"
+#include "rules.h"
+#include "scan.h"
+#include "search.h"
+#include "strings.h"
+#include "timestamp.h"
+#include "variable.h"
 
 /* Macintosh is "special" */
 #ifdef OS_MAC
- #include <QuickDraw.h>
+# include <QuickDraw.h>
 #endif
 
 /* And UNIX for this. */
 #ifdef unix
- #include <sys/utsname.h>
- #include <signal.h>
+# include <sys/utsname.h>
+# include <signal.h>
 #endif
 
 struct globs globs =
@@ -152,7 +145,8 @@
     { 0, 1 }, /* debug ... */
 #endif
     0, /* output commands, not run them */
- 0 /* action timeout */
+ 0, /* action timeout */
+ 0 /* maximum buffer size zero is all output */
 };
 
 /* Symbols to be defined as true for use in Jambase. */
@@ -165,27 +159,27 @@
  */
 
 #ifdef OS_MAC
- #define use_environ arg_environ
- #ifdef MPW
- QDGlobals qd;
- #endif
+# define use_environ arg_environ
+# ifdef MPW
+ QDGlobals qd;
+# endif
 #endif
 
 /* on Win32-LCC */
 #if defined( OS_NT ) && defined( __LCC__ )
- #define use_environ _environ
+# define use_environ _environ
 #endif
 
-# if defined( __MWERKS__)
- #define use_environ _environ
+#if defined( __MWERKS__)
+# define use_environ _environ
     extern char * * _environ;
 #endif
 
 #ifndef use_environ
- #define use_environ environ
- #if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
- extern char **environ;
- #endif
+# define use_environ environ
+# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
+ extern char **environ;
+# endif
 #endif
 
 #if YYDEBUG != 0
@@ -195,10 +189,10 @@
 #ifndef NDEBUG
 static void run_unit_tests()
 {
-#if defined( USE_EXECNT )
+# if defined( USE_EXECNT )
     extern void execnt_unit_test();
     execnt_unit_test();
-#endif
+# endif
     string_unit_test();
 }
 #endif
@@ -216,32 +210,32 @@
 
 void regex_done();
 
-const char *saved_argv0;
+char const * saved_argv0;
 
 int main( int argc, char * * argv, char * * arg_environ )
 {
     int n;
     char * s;
- struct bjam_option optv[N_OPTS];
+ struct bjam_option optv[ N_OPTS ];
     char const * all = "all";
     int status;
     int arg_c = argc;
     char * * arg_v = argv;
- char const * progname = argv[0];
+ char const * progname = argv[ 0 ];
     module_t * environ_module;
 
- saved_argv0 = argv[0];
+ saved_argv0 = argv[ 0 ];
 
     BJAM_MEM_INIT();
 
-# ifdef OS_MAC
- InitGraf(&qd.thePort);
-# endif
+#ifdef OS_MAC
+ InitGraf( &qd.thePort );
+#endif
 
     --argc;
     ++argv;
 
- if ( getoptions( argc, argv, "-:l:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
+ if ( getoptions( argc, argv, "-:l:m:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
     {
         printf( "\nusage: %s [ options ] targets...\n\n", progname );
 
@@ -251,6 +245,7 @@
         /* printf( "-g Build from newest sources first.\n" ); */
         printf( "-jx Run up to x shell commands concurrently.\n" );
         printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" );
+ printf( "-mx Maximum target output saved (kb), default is to save all output.\n" );
         printf( "-n Don't actually execute the updating actions.\n" );
         printf( "-ox Write the updating actions to file x.\n" );
         printf( "-px x=0, pipes action stdout and stderr merged into action output.\n" );
@@ -266,20 +261,22 @@
     /* Version info. */
     if ( ( s = getoptval( optv, 'v', 0 ) ) )
     {
- printf( "Boost.Jam " );
- printf( "Version %s. %s.\n", VERSION, OSMINOR );
- printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. \n" );
+ printf( "Boost.Jam Version %s. %s.\n", VERSION, OSMINOR );
+ printf( " Copyright 1993-2002 Christopher Seiwald and Perforce "
+ "Software, Inc.\n" );
         printf( " Copyright 2001 David Turner.\n" );
         printf( " Copyright 2001-2004 David Abrahams.\n" );
         printf( " Copyright 2002-2008 Rene Rivera.\n" );
         printf( " Copyright 2003-2008 Vladimir Prus.\n" );
-
         return EXITOK;
     }
 
     /* Pick up interesting options. */
     if ( ( s = getoptval( optv, 'n', 0 ) ) )
- globs.noexec++, globs.debug[2] = 1;
+ {
+ ++globs.noexec;
+ globs.debug[ 2 ] = 1;
+ }
 
     if ( ( s = getoptval( optv, 'p', 0 ) ) )
     {
@@ -287,11 +284,10 @@
          * stdout and stderr.
          */
         globs.pipe_action = atoi( s );
- if ( ( 3 < globs.pipe_action ) || ( globs.pipe_action < 0 ) )
+ if ( globs.pipe_action < 0 || 3 < globs.pipe_action )
         {
- printf(
- "Invalid pipe descriptor '%d', valid values are -p[0..3].\n",
- globs.pipe_action );
+ printf( "Invalid pipe descriptor '%d', valid values are -p[0..3]."
+ "\n", globs.pipe_action );
             exit( EXITBAD );
         }
     }
@@ -305,10 +301,11 @@
     if ( ( s = getoptval( optv, 'j', 0 ) ) )
     {
         globs.jobs = atoi( s );
- if (globs.jobs == 0)
+ if ( globs.jobs < 1 || globs.jobs > MAXJOBS )
         {
- printf("Invalid value for the '-j' option.\n");
- exit(EXITBAD);
+ printf( "Invalid value for the '-j' option, valid values are 1 "
+ "through %d.\n", MAXJOBS );
+ exit( EXITBAD );
         }
     }
 
@@ -318,6 +315,9 @@
     if ( ( s = getoptval( optv, 'l', 0 ) ) )
         globs.timeout = atoi( s );
 
+ if ( ( s = getoptval( optv, 'm', 0 ) ) )
+ globs.max_buf = atoi( s ) * 1024; /* convert to kb */
+
     /* Turn on/off debugging */
     for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n )
     {
@@ -339,12 +339,13 @@
         /* n turns on levels 1-n. */
         /* +n turns on level n. */
         if ( *s == '+' )
- globs.debug[i] = 1;
+ globs.debug[ i ] = 1;
         else while ( i )
- globs.debug[i--] = 1;
+ globs.debug[ i-- ] = 1;
     }
 
     constants_init();
+ cwd_init();
 
     {
         PROFILE_ENTER( MAIN );
@@ -385,7 +386,12 @@
 #endif
 
         /* Set JAMDATE. */
- var_set( root_module(), constant_JAMDATE, list_new( outf_time(time(0)) ), VAR_SET );
+ {
+ timestamp current;
+ timestamp_current( &current );
+ var_set( root_module(), constant_JAMDATE, list_new( outf_time(
+ &current ) ), VAR_SET );
+ }
 
         /* Set JAM_VERSION. */
         var_set( root_module(), constant_JAM_VERSION,
@@ -415,7 +421,15 @@
                              object_new( u.machine ) ), VAR_SET );
             }
         }
-#endif /* unix */
+#endif /* unix */
+
+ /* Set JAM_TIMESTAMP_RESOLUTION. */
+ {
+ timestamp fmt_resolution[ 1 ];
+ file_supported_fmt_resolution( fmt_resolution );
+ var_set( root_module(), constant_JAM_TIMESTAMP_RESOLUTION, list_new(
+ object_new( timestamp_timestr( fmt_resolution ) ) ), VAR_SET );
+ }
 
         /* Load up environment variables. */
 
@@ -438,7 +452,7 @@
         /* Load up variables set on command line. */
         for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n )
         {
- char *symv[2];
+ char * symv[ 2 ];
             symv[ 0 ] = s;
             symv[ 1 ] = 0;
             var_defines( root_module(), symv, 1 );
@@ -448,9 +462,8 @@
         /* Set the ARGV to reflect the complete list of arguments of invocation.
          */
         for ( n = 0; n < arg_c; ++n )
- {
- var_set( root_module(), constant_ARGV, list_new( object_new( arg_v[n] ) ), VAR_APPEND );
- }
+ var_set( root_module(), constant_ARGV, list_new( object_new(
+ arg_v[ n ] ) ), VAR_APPEND );
 
         /* Initialize built-in rules. */
         load_builtins();
@@ -466,16 +479,14 @@
             }
             else
             {
- OBJECT * target = object_new( arg_v[ n ] );
+ OBJECT * const target = object_new( arg_v[ n ] );
                 mark_target_for_updating( target );
                 object_free( target );
             }
         }
 
         if ( list_empty( targets_to_update() ) )
- {
             mark_target_for_updating( constant_all );
- }
 
         /* Parse ruleset. */
         {
@@ -483,15 +494,13 @@
             frame_init( frame );
             for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n )
             {
- OBJECT * filename = object_new( s );
+ OBJECT * const filename = object_new( s );
                 parse_file( filename, frame );
                 object_free( filename );
             }
 
             if ( !n )
- {
                 parse_file( constant_plus, frame );
- }
         }
 
         status = yyanyerrors();
@@ -499,7 +508,7 @@
         /* Manually touch -t targets. */
         for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n )
         {
- OBJECT * target = object_new( s );
+ OBJECT * const target = object_new( s );
             touch_target( target );
             object_free( target );
         }
@@ -516,52 +525,37 @@
         }
 
         /* The build system may set the PARALLELISM variable to override -j
- options. */
+ * options.
+ */
         {
- LIST *p = L0;
- p = var_get ( root_module(), constant_PARALLELISM );
+ LIST * const p = var_get( root_module(), constant_PARALLELISM );
             if ( !list_empty( p ) )
             {
- int j = atoi( object_str( list_front( p ) ) );
- if ( j == -1 )
- {
- printf( "Invalid value of PARALLELISM: %s\n", object_str( list_front( p ) ) );
- }
+ int const j = atoi( object_str( list_front( p ) ) );
+ if ( j < 1 || j > MAXJOBS )
+ printf( "Invalid value of PARALLELISM: %s. Valid values "
+ "are 1 through %d.\n", object_str( list_front( p ) ),
+ MAXJOBS );
                 else
- {
                     globs.jobs = j;
- }
             }
         }
 
         /* KEEP_GOING overrides -q option. */
         {
- LIST *p = L0;
- p = var_get( root_module(), constant_KEEP_GOING );
+ LIST * const p = var_get( root_module(), constant_KEEP_GOING );
             if ( !list_empty( p ) )
- {
- int v = atoi( object_str( list_front( p ) ) );
- if ( v == 0 )
- globs.quitquick = 1;
- else
- globs.quitquick = 0;
- }
+ globs.quitquick = atoi( object_str( list_front( p ) ) ) ? 0 : 1;
         }
 
         /* Now make target. */
         {
             PROFILE_ENTER( MAIN_MAKE );
-
- LIST * targets = targets_to_update();
+ LIST * const targets = targets_to_update();
             if ( !list_empty( targets ) )
- {
                 status |= make( targets, anyhow );
- }
             else
- {
                 status = last_update_now_status;
- }
-
             PROFILE_EXIT( MAIN_MAKE );
         }
 
@@ -571,7 +565,7 @@
     if ( DEBUG_PROFILE )
         profile_dump();
 
-
+
 #ifdef OPT_HEADER_CACHE_EXT
     hcache_done();
 #endif
@@ -579,15 +573,15 @@
     clear_targets_to_update();
 
     /* Widely scattered cleanup. */
+ property_set_done();
     file_done();
     rules_done();
- stamps_done();
+ timestamp_done();
     search_done();
     class_done();
     modules_done();
     regex_done();
- exec_done();
- pwd_done();
+ cwd_done();
     path_done();
     function_done();
     list_done();
@@ -607,56 +601,56 @@
     return status ? EXITBAD : EXITOK;
 }
 
+
+/*
+ * executable_path()
+ */
+
 #if defined(_WIN32)
-#include <windows.h>
-char *executable_path(const char *argv0) {
- char buf[1024];
- DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf));
- if (ret == 0 || ret == sizeof(buf)) return NULL;
- return strdup (buf);
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+char * executable_path( char const * argv0 )
+{
+ char buf[ 1024 ];
+ DWORD const ret = GetModuleFileName( NULL, buf, sizeof( buf ) );
+ return ( !ret || ret == sizeof( buf ) ) ? NULL : strdup( buf );
 }
 #elif defined(__APPLE__) /* Not tested */
-#include <mach-o/dyld.h>
-char *executable_path(const char *argv0) {
- char buf[1024];
- uint32_t size = sizeof(buf);
- int ret = _NSGetExecutablePath(buf, &size);
- if (ret != 0) return NULL;
- return strdup(buf);
+# include <mach-o/dyld.h>
+char *executable_path( char const * argv0 )
+{
+ char buf[ 1024 ];
+ uint32_t size = sizeof( buf );
+ return _NSGetExecutablePath( buf, &size ) ? NULL : strdup( buf );
 }
-#elif defined(sun) || defined(__sun) /* Not tested */
-#include <stdlib.h>
-
-char *executable_path(const char *argv0) {
- return strdup(getexecname());
+#elif defined(sun) || defined(__sun) /* Not tested */
+# include <stdlib.h>
+char * executable_path( char const * argv0 )
+{
+ return strdup( getexecname() );
 }
 #elif defined(__FreeBSD__)
-#include <sys/sysctl.h>
-char *executable_path(const char *argv0) {
- int mib[4];
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PATHNAME;
- mib[3] = -1;
- char buf[1024];
- size_t size = sizeof(buf);
- sysctl(mib, 4, buf, &size, NULL, 0);
- if (size == 0 || size == sizeof(buf)) return NULL;
- return strndup(buf, size);
+# include <sys/sysctl.h>
+char * executable_path( char const * argv0 )
+{
+ int mib[ 4 ] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ char buf[ 1024 ];
+ size_t size = sizeof( buf );
+ sysctl( mib, 4, buf, &size, NULL, 0 );
+ return ( !size || size == sizeof( buf ) ) ? NULL : strndup( buf, size );
 }
 #elif defined(__linux__)
-#include <unistd.h>
-char *executable_path(const char *argv0) {
- char buf[1024];
- ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf));
- if (ret == 0 || ret == sizeof(buf)) return NULL;
- return strndup(buf, ret);
+# include <unistd.h>
+char * executable_path( char const * argv0 )
+{
+ char buf[ 1024 ];
+ ssize_t const ret = readlink( "/proc/self/exe", buf, sizeof( buf ) );
+ return ( !ret || ret == sizeof( buf ) ) ? NULL : strndup( buf, ret );
 }
 #else
-char *executable_path(const char *argv0) {
- /* If argv0 is absolute path, assume it's the right absolute path. */
- if (argv0[0] == '/')
- return strdup(argv0);
- return NULL;
+char * executable_path( char const * argv0 )
+{
+ /* If argv0 is an absolute path, assume it is the right absolute path. */
+ return argv0[ 0 ] == '/' ? strdup( argv0 ) : NULL;
 }
 #endif

Modified: branches/release/tools/build/v2/engine/jam.h
==============================================================================
--- branches/release/tools/build/v2/engine/jam.h (original)
+++ branches/release/tools/build/v2/engine/jam.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,35 +4,15 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * 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)
  */
 
 /*
  * jam.h - includes and globals for jam
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 04/21/94 (seiwald) - DGUX is __DGUX__, not just __DGUX.
- * 05/04/94 (seiwald) - new globs.jobs (-j jobs)
- * 11/01/94 (wingerd) - let us define path of Jambase at compile time.
- * 12/30/94 (wingerd) - changed command buffer size for NT (MS-DOS shell).
- * 02/22/95 (seiwald) - Jambase now in /usr/local/lib.
- * 04/30/95 (seiwald) - FreeBSD added. Live Free or Die.
- * 05/10/95 (seiwald) - SPLITPATH character set up here.
- * 08/20/95 (seiwald) - added LINUX.
- * 08/21/95 (seiwald) - added NCR.
- * 10/23/95 (seiwald) - added SCO.
- * 01/03/96 (seiwald) - SINIX (nixdorf) added.
- * 03/13/96 (seiwald) - Jambase now compiled in; remove JAMBASE variable.
- * 04/29/96 (seiwald) - AIX now has 31 and 42 OSVERs.
- * 11/21/96 (peterk) - added BeOS with MW CW mwcc
- * 12/21/96 (seiwald) - OSPLAT now defined for NT.
- * 07/19/99 (sickel) - Mac OS X Server and Client support added
- * 02/18/00 (belmonte)- Support for Cygwin.
- * 09/12/00 (seiwald) - OSSYMS split to OSMAJOR/OSMINOR/OSPLAT
- * 12/29/00 (seiwald) - OSVER dropped.
  */
 
 #ifndef JAM_H_VP_2003_08_01
@@ -51,14 +31,14 @@
 
 #ifdef NT
 
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
 #include <ctype.h>
+#include <fcntl.h>
 #include <malloc.h>
 #ifndef __MWERKS__
     #include <memory.h>
 #endif
+#include <stdio.h>
+#include <stdlib.h>
 #include <signal.h>
 #include <string.h>
 #include <time.h>
@@ -67,14 +47,9 @@
 #define OSMINOR "OS=NT"
 #define OS_NT
 #define SPLITPATH ';'
-/* Windows NT 3.51 only allows 996 chars per line, but we deal with the problem
- * in "execnt.c".
- */
-#define MAXLINE (maxline()) /* longest 'together' actions */
+#define MAXLINE (undefined__see_execnt_c) /* max chars per command line */
 #define USE_EXECNT
-#define USE_PATHUNIX
 #define PATH_DELIM '\\'
-#define DOWNSHIFT_PATHS
 
 /* AS400 cross-compile from NT. */
 
@@ -92,7 +67,8 @@
     #undef HAVE_POPEN
 #endif
 
-# endif
+#endif /* #ifdef NT */
+
 
 /*
  * Windows MingW32
@@ -114,13 +90,12 @@
 #define OSMINOR "OS=MINGW"
 #define OS_NT
 #define SPLITPATH ';'
-#define MAXLINE 996 /* longest 'together' actions */
+#define MAXLINE 996 /* max chars per command line */
 #define USE_EXECUNIX
-#define USE_PATHUNIX
 #define PATH_DELIM '\\'
-#define DOWNSHIFT_PATHS
 
-#endif
+#endif /* #ifdef MINGW */
+
 
 /*
  * God fearing UNIX.
@@ -131,12 +106,11 @@
 #define OSMAJOR "UNIX=true"
 #define USE_EXECUNIX
 #define USE_FILEUNIX
-#define USE_PATHUNIX
 #define PATH_DELIM '/'
 
 #ifdef _AIX
     #define unix
- #define MAXLINE 23552 /* 24k - 1k, longest 'together' actions */
+ #define MAXLINE 23552 /* 24k - 1k, max chars per command line */
     #define OSMINOR "OS=AIX"
     #define OS_AIX
     #define NO_VFORK
@@ -240,7 +214,7 @@
         #define OSMINOR "OS=QNX"
         #define OS_QNX
         #define NO_VFORK
- #define MAXLINE 996
+ #define MAXLINE 996 /* max chars per command line */
     #endif
 #endif
 #ifdef NeXT
@@ -315,7 +289,6 @@
 /* All the UNIX includes */
 
 #include <sys/types.h>
-#include <sys/stat.h>
 
 #ifndef OS_MPEIX
     #include <sys/file.h>
@@ -349,7 +322,8 @@
     #include <malloc.h>
 #endif
 
-#endif
+#endif /* #ifndef OSMINOR */
+
 
 /*
  * OSPLAT definitions - suppressed when it is a one-of-a-kind.
@@ -387,7 +361,6 @@
     #define OSPLAT "OSPLAT=X86_64"
 #endif
 
-
 #if defined( __sparc__ ) || \
     defined( __sparc )
     #define OSPLAT "OSPLAT=SPARC"
@@ -413,12 +386,13 @@
     #define OSPLAT ""
 #endif
 
+
 /*
  * Jam implementation misc.
  */
 
 #ifndef MAXLINE
- #define MAXLINE 102400 /* longest 'together' actions' */
+ #define MAXLINE 102400 /* max chars per command line */
 #endif
 
 #ifndef EXITOK
@@ -435,7 +409,7 @@
 #define MAXSYM 1024 /* longest symbol in the environment */
 #define MAXJPATH 1024 /* longest filename */
 
-#define MAXJOBS 64 /* silently enforced -j limit */
+#define MAXJOBS 64 /* internally enforced -j limit */
 #define MAXARGC 32 /* words in $(JAMSHELL) */
 
 /* Jam private definitions below. */
@@ -455,7 +429,12 @@
     long timeout; /* number of seconds to limit actions to,
                                  * default 0 for no limit.
                                  */
- int dart; /* output build and test results formatted for Dart */
+ int dart; /* output build and test results formatted for
+ * Dart
+ */
+ int max_buf; /* maximum amount of output saved from target
+ * (kb)
+ */
 };
 
 extern struct globs globs;
@@ -463,7 +442,7 @@
 #define DEBUG_MAKE ( globs.debug[ 1 ] ) /* show actions when executed */
 #define DEBUG_MAKEQ ( globs.debug[ 2 ] ) /* show even quiet actions */
 #define DEBUG_EXEC ( globs.debug[ 2 ] ) /* show text of actons */
-#define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* show progress of make0 */
+#define DEBUG_MAKEPROG ( globs.debug[ 3 ] ) /* show make0 progress */
 #define DEBUG_BIND ( globs.debug[ 3 ] ) /* show when files bound */
 
 #define DEBUG_EXECCMD ( globs.debug[ 4 ] ) /* show execcmds()'s work */
@@ -472,7 +451,7 @@
 
 #define DEBUG_HEADER ( globs.debug[ 6 ] ) /* show result of header scan */
 #define DEBUG_BINDSCAN ( globs.debug[ 6 ] ) /* show result of dir scan */
-#define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show attempts at binding */
+#define DEBUG_SEARCH ( globs.debug[ 6 ] ) /* show binding attempts */
 
 #define DEBUG_VARSET ( globs.debug[ 7 ] ) /* show variable settings */
 #define DEBUG_VARGET ( globs.debug[ 8 ] ) /* show variable fetches */
@@ -485,7 +464,7 @@
 #define DEBUG_PROFILE ( globs.debug[ 10 ] ) /* dump rule execution times */
 #define DEBUG_PARSE ( globs.debug[ 11 ] ) /* debug parsing */
 #define DEBUG_GRAPH ( globs.debug[ 12 ] ) /* debug dependencies */
-#define DEBUG_FATE ( globs.debug[ 13 ] ) /* show changes to fate in make0() */
+#define DEBUG_FATE ( globs.debug[ 13 ] ) /* show fate changes in make0() */
 
 /* Everyone gets the memory definitions. */
 #include "mem.h"

Modified: branches/release/tools/build/v2/engine/lists.c
==============================================================================
--- branches/release/tools/build/v2/engine/lists.c (original)
+++ branches/release/tools/build/v2/engine/lists.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,21 +4,16 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-# include "jam.h"
-# include "object.h"
-# include "lists.h"
-# include "assert.h"
-
 /*
  * lists.c - maintain lists of objects
- *
- * 08/23/94 (seiwald) - new list_append()
- * 09/07/00 (seiwald) - documented lol_*() functions
  */
 
-struct freelist_node { struct freelist_node *next; };
+#include "jam.h"
+#include "lists.h"
+
+#include <assert.h>
 
-static struct freelist_node *freelist[32]; /* junkpile for list_free() */
+static LIST * freelist[ 32 ]; /* junkpile for list_dealloc() */
 
 static unsigned get_bucket( unsigned size )
 {
@@ -27,42 +22,35 @@
     return bucket;
 }
 
-static LIST * list_alloc( unsigned size )
+static LIST * list_alloc( unsigned const size )
 {
- unsigned bucket = get_bucket( size );
+ unsigned const bucket = get_bucket( size );
     if ( freelist[ bucket ] )
     {
- struct freelist_node * result = freelist[ bucket ];
- freelist[ bucket ] = result->next;
- return (LIST *)result;
- }
- else
- {
- return (LIST *)BJAM_MALLOC( sizeof( LIST ) + ( 1u << bucket ) * sizeof( OBJECT * ) );
+ LIST * result = freelist[ bucket ];
+ freelist[ bucket ] = result->impl.next;
+ return result;
     }
+ return (LIST *)BJAM_MALLOC( sizeof( LIST ) + ( 1u << bucket ) *
+ sizeof( OBJECT * ) );
 }
 
 static void list_dealloc( LIST * l )
 {
     unsigned size = list_length( l );
     unsigned bucket;
- struct freelist_node * node = (struct freelist_node *)l;
+ LIST * node = l;
 
     if ( size == 0 ) return;
 
     bucket = get_bucket( size );;
 
 #ifdef BJAM_NO_MEM_CACHE
-
     BJAM_FREE( node );
-
 #else
-
- node->next = freelist[ bucket ];
+ node->impl.next = freelist[ bucket ];
     freelist[ bucket ] = node;
-
 #endif
-
 }
 
 /*
@@ -71,74 +59,48 @@
 
 LIST * list_append( LIST * l, LIST * nl )
 {
- if ( list_empty( nl ) )
- {
- /* Just return l */
- }
- else if ( list_empty( l ) )
- {
- l = nl;
- }
- else
+ if ( list_empty( l ) )
+ return nl;
+ if ( !list_empty( nl ) )
     {
- int l_size = list_length( l );
- int nl_size = list_length( nl );
- int size = l_size + nl_size;
- unsigned bucket;
- int i;
+ int const l_size = list_length( l );
+ int const nl_size = list_length( nl );
+ int const size = l_size + nl_size;
+ unsigned const bucket = get_bucket( size );
 
- bucket = get_bucket( size );
         /* Do we need to reallocate? */
- if ( l_size <= ( 1u << (bucket - 1) ) )
+ if ( l_size <= ( 1u << ( bucket - 1 ) ) )
         {
             LIST * result = list_alloc( size );
- memcpy( list_begin( result ), list_begin( l ), l_size * sizeof( OBJECT * ) );
+ memcpy( list_begin( result ), list_begin( l ), l_size * sizeof(
+ OBJECT * ) );
             list_dealloc( l );
             l = result;
         }
 
         l->impl.size = size;
- memcpy( list_begin( l ) + l_size, list_begin( nl ), nl_size * sizeof( OBJECT * ) );
+ memcpy( list_begin( l ) + l_size, list_begin( nl ), nl_size * sizeof(
+ OBJECT * ) );
         list_dealloc( nl );
- return l;
     }
-
     return l;
 }
 
 LISTITER list_begin( LIST * l )
 {
- if ( l )
- return (LISTITER)( (char *)l + sizeof(LIST) );
- else
- return 0;
+ return l ? (LISTITER)( (char *)l + sizeof( LIST ) ) : 0;
 }
 
 LISTITER list_end( LIST * l )
 {
- if ( l )
- return list_begin( l ) + l->impl.size;
- else
- return 0;
+ return l ? list_begin( l ) + l->impl.size : 0;
 }
 
 LIST * list_new( OBJECT * value )
-{
- LIST * head;
- if ( freelist[ 0 ] )
- {
- struct freelist_node * result = freelist[ 0 ];
- freelist[ 0 ] = result->next;
- head = (LIST *)result;
- }
- else
- {
- head = BJAM_MALLOC( sizeof( LIST * ) + sizeof( OBJECT * ) );
- }
-
+{
+ LIST * const head = list_alloc( 1 ) ;
     head->impl.size = 1;
     list_begin( head )[ 0 ] = value;
-
     return head;
 }
 
@@ -189,19 +151,15 @@
     result = list_alloc( size );
     result->impl.size = size;
     for ( i = 0; i < size; ++i )
- {
         list_begin( result )[ i ] = object_copy( list_begin( l )[ i ] );
- }
     return result;
 }
 
 
-LIST * list_copy_range( LIST *l, LISTITER first, LISTITER last )
+LIST * list_copy_range( LIST * l, LISTITER first, LISTITER last )
 {
     if ( first == last )
- {
         return L0;
- }
     else
     {
         int size = last - first;
@@ -209,9 +167,7 @@
         LISTITER dest = list_begin( result );
         result->impl.size = size;
         for ( ; first != last; ++first, ++dest )
- {
             *dest = object_copy( *first );
- }
         return result;
     }
 }
@@ -235,7 +191,7 @@
 {
     OBJECT * a = *( (OBJECT * *)va );
     OBJECT * b = *( (OBJECT * *)vb );
- return strcmp(object_str(a), object_str(b));
+ return strcmp( object_str( a ), object_str( b ) );
 }
 
 
@@ -265,11 +221,10 @@
 {
     if ( !list_empty( head ) )
     {
- LISTITER iter = list_begin( head ), end = list_end( head );
+ LISTITER iter = list_begin( head );
+ LISTITER const end = list_end( head );
         for ( ; iter != end; iter = list_next( iter ) )
- {
             object_free( list_item( iter ) );
- }
         list_dealloc( head );
     }
 }
@@ -282,7 +237,7 @@
 LIST * list_pop_front( LIST * l )
 {
     unsigned size = list_length( l );
- assert( size != 0 );
+ assert( size );
     --size;
     object_free( list_front( l ) );
 
@@ -291,35 +246,33 @@
         list_dealloc( l );
         return L0;
     }
- else if ( ( ( size - 1 ) & size ) == 0 )
+
+ if ( ( ( size - 1 ) & size ) == 0 )
     {
- LIST * nl = list_alloc( size );
+ LIST * const nl = list_alloc( size );
         nl->impl.size = size;
- memcpy( list_begin( nl ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
+ memcpy( list_begin( nl ), list_begin( l ) + 1, size * sizeof( OBJECT * )
+ );
         list_dealloc( l );
         return nl;
     }
- else
- {
- l->impl.size = size;
- memmove( list_begin( l ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
- return l;
- }
+
+ l->impl.size = size;
+ memmove( list_begin( l ), list_begin( l ) + 1, size * sizeof( OBJECT * ) );
+ return l;
 }
 
-LIST * list_reverse( LIST * l )
+LIST * list_reverse( LIST * l )
 {
     int size = list_length( l );
     if ( size == 0 ) return L0;
- else
     {
- LIST * result = list_alloc( size );
+ LIST * const result = list_alloc( size );
         int i;
         result->impl.size = size;
         for ( i = 0; i < size; ++i )
- {
- list_begin( result )[ i ] = object_copy( list_begin( l )[ size - i - 1 ] );
- }
+ list_begin( result )[ i ] = object_copy( list_begin( l )[ size - i -
+ 1 ] );
         return result;
     }
 }
@@ -327,13 +280,15 @@
 int list_cmp( LIST * t, LIST * s )
 {
     int status = 0;
- LISTITER t_it = list_begin( t ), t_end = list_end( t );
- LISTITER s_it = list_begin( s ), s_end = list_end( s );
+ LISTITER t_it = list_begin( t );
+ LISTITER const t_end = list_end( t );
+ LISTITER s_it = list_begin( s );
+ LISTITER const s_end = list_end( s );
 
     while ( !status && ( t_it != t_end || s_it != s_end ) )
     {
- const char *st = t_it != t_end ? object_str( list_item( t_it ) ) : "";
- const char *ss = s_it != s_end ? object_str( list_item( s_it ) ) : "";
+ char const * st = t_it != t_end ? object_str( list_item( t_it ) ) : "";
+ char const * ss = s_it != s_end ? object_str( list_item( s_it ) ) : "";
 
         status = strcmp( st, ss );
 
@@ -346,12 +301,11 @@
 
 int list_is_sublist( LIST * sub, LIST * l )
 {
- LISTITER iter = list_begin( sub ), end = list_end( sub );
+ LISTITER iter = list_begin( sub );
+ LISTITER const end = list_end( sub );
     for ( ; iter != end; iter = list_next( iter ) )
- {
         if ( !list_in( l, list_item( iter ) ) )
             return 0;
- }
     return 1;
 }
 
@@ -378,16 +332,14 @@
 
 int list_length( LIST * l )
 {
- if ( l )
- return l->impl.size;
- else
- return 0;
+ return l ? l->impl.size : 0;
 }
 
 
 int list_in( LIST * l, OBJECT * value )
 {
- LISTITER iter = list_begin( l ), end = list_end( l );
+ LISTITER iter = list_begin( l );
+ LISTITER end = list_end( l );
     for ( ; iter != end; iter = list_next( iter ) )
         if ( object_equal( list_item( iter ), value ) )
             return 1;
@@ -415,15 +367,13 @@
 void list_done()
 {
     int i;
- int total = 0;
     for ( i = 0; i < sizeof( freelist ) / sizeof( freelist[ 0 ] ); ++i )
     {
- struct freelist_node *l, *tmp;
- int bytes;
- for( l = freelist[ i ]; l; )
+ LIST * l = freelist[ i ];
+ while ( l )
         {
- tmp = l;
- l = l->next;
+ LIST * const tmp = l;
+ l = l->impl.next;
             BJAM_FREE( tmp );
         }
     }
@@ -481,7 +431,6 @@
 void lol_print( LOL * lol )
 {
     int i;
-
     for ( i = 0; i < lol->count; ++i )
     {
         if ( i )
@@ -492,32 +441,32 @@
 
 #ifdef HAVE_PYTHON
 
-PyObject *list_to_python(LIST *l)
+PyObject * list_to_python( LIST * l )
 {
- PyObject *result = PyList_New(0);
- LISTITER iter = list_begin( l ), end = list_end( l );
-
- for (; iter != end; iter = list_next( iter ) )
+ PyObject * result = PyList_New( 0 );
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
     {
- PyObject* s = PyString_FromString(object_str(list_item(iter)));
- PyList_Append(result, s);
- Py_DECREF(s);
+ PyObject * s = PyString_FromString( object_str( list_item( iter ) ) );
+ PyList_Append( result, s );
+ Py_DECREF( s );
     }
 
     return result;
 }
 
-LIST *list_from_python(PyObject *l)
+LIST * list_from_python( PyObject * l )
 {
     LIST * result = L0;
 
- Py_ssize_t i, n;
- n = PySequence_Size(l);
- for (i = 0; i < n; ++i)
- {
- PyObject *v = PySequence_GetItem(l, i);
- result = list_push_back(result, object_new (PyString_AsString(v)));
- Py_DECREF(v);
+ Py_ssize_t n = PySequence_Size( l );
+ Py_ssize_t i;
+ for ( i = 0; i < n; ++i )
+ {
+ PyObject * v = PySequence_GetItem( l, i );
+ result = list_push_back( result, object_new( PyString_AsString( v ) ) );
+ Py_DECREF( v );
     }
 
     return result;

Modified: branches/release/tools/build/v2/engine/lists.h
==============================================================================
--- branches/release/tools/build/v2/engine/lists.h (original)
+++ branches/release/tools/build/v2/engine/lists.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -13,9 +13,8 @@
 /*
  * lists.h - the LIST structure and routines to manipulate them
  *
- * The whole of jam relies on lists of objects as a datatype. This
- * module, in conjunction with object.c, handles these relatively
- * efficiently.
+ * The whole of jam relies on lists of objects as a datatype. This module, in
+ * conjunction with object.c, handles these relatively efficiently.
  *
  * Structures defined:
  *
@@ -37,32 +36,28 @@
  * lol_free() - free the LOL and its LISTs
  * lol_get() - return one of the LISTs in the LOL
  * lol_print() - debug print LISTS separated by ":"
- *
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 08/23/94 (seiwald) - new list_append()
  */
 
 #ifndef LISTS_DWA20011022_H
-# define LISTS_DWA20011022_H
+#define LISTS_DWA20011022_H
 
 #include "object.h"
 
 #ifdef HAVE_PYTHON
-#include <Python.h>
+# include <Python.h>
 #endif
 
 /*
  * LIST - list of strings
  */
 
-typedef struct _list LIST;
-
-struct _list {
+typedef struct _list {
     union {
         int size;
- OBJECT *align;
+ struct _list * next;
+ OBJECT * align;
     } impl;
-};
+} LIST;
 
 typedef OBJECT * * LISTITER;
 
@@ -70,55 +65,49 @@
  * LOL - list of LISTs
  */
 
-typedef struct _lol LOL;
-
-# define LOL_MAX 19
-
-struct _lol {
+#define LOL_MAX 19
+typedef struct _lol {
     int count;
- LIST *list[ LOL_MAX ];
-};
+ LIST * list[ LOL_MAX ];
+} LOL;
 
-LIST * list_new( OBJECT * value );
-LIST * list_append( LIST *l, LIST *nl );
-LIST * list_copy( LIST *l );
-LIST * list_copy_range( LIST *l, LISTITER first, LISTITER last );
-void list_free( LIST *head );
-LIST * list_push_back( LIST *head, OBJECT *string );
-void list_print( LIST *l );
-int list_length( LIST *l );
-LIST * list_sublist( LIST *l, int start, int count );
-LIST * list_pop_front( LIST *l );
-LIST * list_sort( LIST *l);
-LIST * list_unique( LIST *sorted_list);
-int list_in(LIST* l, OBJECT* value);
-LIST * list_reverse( LIST * );
-int list_cmp( LIST * lhs, LIST * rhs );
-int list_is_sublist( LIST * sub, LIST * l );
-void list_done();
+LIST * list_new( OBJECT * value );
+LIST * list_append( LIST * destination, LIST * source );
+LIST * list_copy( LIST * );
+LIST * list_copy_range( LIST * destination, LISTITER first, LISTITER last );
+void list_free( LIST * head );
+LIST * list_push_back( LIST * head, OBJECT * value );
+void list_print( LIST * );
+int list_length( LIST * );
+LIST * list_sublist( LIST *, int start, int count );
+LIST * list_pop_front( LIST * );
+LIST * list_sort( LIST * );
+LIST * list_unique( LIST * sorted_list );
+int list_in( LIST *, OBJECT * value );
+LIST * list_reverse( LIST * );
+int list_cmp( LIST * lhs, LIST * rhs );
+int list_is_sublist( LIST * sub, LIST * l );
+void list_done();
 
 LISTITER list_begin( LIST * );
 LISTITER list_end( LIST * );
-# define list_next( it ) ((it) + 1)
-# define list_item( it ) (*(it))
-# define list_empty( l ) ( (l) == L0 )
-# define list_front( l ) list_item( list_begin( l ) )
-
-# define L0 ((LIST *)0)
-
-void lol_add( LOL *lol, LIST *l );
-void lol_init( LOL *lol );
-void lol_free( LOL *lol );
-LIST * lol_get( LOL *lol, int i );
-void lol_print( LOL *lol );
-void lol_build( LOL* lol, const char** elements );
+#define list_next( it ) ((it) + 1)
+#define list_item( it ) (*(it))
+#define list_empty( l ) ((l) == L0)
+#define list_front( l ) list_item( list_begin( l ) )
+
+#define L0 ((LIST *)0)
+
+void lol_add( LOL *, LIST * );
+void lol_init( LOL * );
+void lol_free( LOL * );
+LIST * lol_get( LOL *, int i );
+void lol_print( LOL * );
+void lol_build( LOL *, char const * * elements );
 
 #ifdef HAVE_PYTHON
-
-PyObject *list_to_python(LIST *l);
-LIST *list_from_python(PyObject *l);
-
+PyObject * list_to_python( LIST * );
+LIST * list_from_python( PyObject * );
 #endif
 
 #endif
-

Modified: branches/release/tools/build/v2/engine/make.c
==============================================================================
--- branches/release/tools/build/v2/engine/make.c (original)
+++ branches/release/tools/build/v2/engine/make.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -27,45 +27,28 @@
  * Internal routines:
  * make0() - bind and scan everything to make a TARGET
  * make0sort() - reorder TARGETS chain by their time (newest to oldest)
- *
- * 12/26/93 (seiwald) - allow NOTIME targets to be expanded via $(<), $(>).
- * 01/04/94 (seiwald) - print all targets, bounded, when tracing commands.
- * 04/08/94 (seiwald) - progress report now reflects only targets with actions.
- * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
- * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
- * 12/20/94 (seiwald) - make0() headers after determining fate of target, so
- * that headers are not seen as being dependent on
- * themselves.
- * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
- * 02/02/95 (seiwald) - propagate leaf source time for new LEAVES rule.
- * 02/14/95 (seiwald) - NOUPDATE rule means don't update existing target.
- * 08/22/95 (seiwald) - NOUPDATE targets immune to anyhow (-a) flag.
- * 09/06/00 (seiwald) - NOCARE affects targets with sources/actions.
- * 03/02/01 (seiwald) - reverse NOCARE change.
- * 03/14/02 (seiwald) - TEMPORARY targets no longer take on parents age.
- * 03/16/02 (seiwald) - support for -g (reorder builds by source time).
  */
 
 #include "jam.h"
+#include "make.h"
 
+#include "command.h"
+#ifdef OPT_HEADER_CACHE_EXT
+# include "hcache.h"
+#endif
+#include "headers.h"
 #include "lists.h"
+#include "object.h"
 #include "parse.h"
-#include "variable.h"
 #include "rules.h"
-
-#ifdef OPT_HEADER_CACHE_EXT
- #include "hcache.h"
-#endif
-
 #include "search.h"
-#include "object.h"
-#include "make.h"
-#include "headers.h"
-#include "command.h"
+#include "timestamp.h"
+#include "variable.h"
+
 #include <assert.h>
 
 #ifndef max
- #define max( a,b ) ((a)>(b)?(a):(b))
+# define max(a,b) ((a)>(b)?(a):(b))
 #endif
 
 static TARGETS * make0sort( TARGETS * c );
@@ -74,7 +57,7 @@
     static void dependGraphOutput( TARGET * t, int depth );
 #endif
 
-static const char * target_fate[] =
+static char const * target_fate[] =
 {
     "init", /* T_FATE_INIT */
     "making", /* T_FATE_MAKING */
@@ -91,7 +74,7 @@
     "nomake" /* T_FATE_CANTMAKE */
 };
 
-static const char * target_bind[] =
+static char const * target_bind[] =
 {
     "unbound",
     "missing",
@@ -99,7 +82,7 @@
     "exists",
 };
 
-# define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) )
+#define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) )
 
 
 /*
@@ -109,7 +92,7 @@
 int make( LIST * targets, int anyhow )
 {
     COUNTS counts[ 1 ];
- int status = 0; /* 1 if anything fails */
+ int status = 0; /* 1 if anything fails */
 
 #ifdef OPT_HEADER_CACHE_EXT
     hcache_init();
@@ -129,7 +112,7 @@
         {
             TARGET * t = bindtarget( list_item( iter ) );
             if ( t->fate == T_FATE_INIT )
- make0( t, 0, 0, counts, anyhow );
+ make0( t, 0, 0, counts, anyhow, 0 );
         }
         PROFILE_EXIT( MAKE_MAKE0 );
     }
@@ -165,10 +148,8 @@
     status = counts->cantfind || counts->cantmake;
 
     {
- LISTITER iter, end;
         PROFILE_ENTER( MAKE_MAKE1 );
- for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
- status |= make1( bindtarget( list_item( iter ) ) );
+ status |= make1( targets );
         PROFILE_EXIT( MAKE_MAKE1 );
     }
 
@@ -240,6 +221,45 @@
 }
 
 
+int make0rescan( TARGET * t, TARGET * rescanning )
+{
+ int result = 0;
+ TARGETS * c;
+
+ /* Check whether we have already found a cycle. */
+ if ( target_scc( t ) == rescanning )
+ return 1;
+
+ /* If we have already visited this node, ignore it. */
+ if ( t->rescanning == rescanning )
+ return 0;
+
+ /* If t is already updated, ignore it. */
+ if ( t->scc_root == NULL && t->progress > T_MAKE_ACTIVE )
+ return 0;
+
+ t->rescanning = rescanning;
+ for ( c = t->depends; c; c = c->next )
+ {
+ TARGET * dependency = c->target;
+ /* Always start at the root of each new strongly connected component. */
+ if ( target_scc( dependency ) != target_scc( t ) )
+ dependency = target_scc( dependency );
+ result |= make0rescan( dependency, rescanning );
+
+ /* Make sure that we pick up the new include node. */
+ if ( c->target->includes == rescanning )
+ result = 1;
+ }
+ if ( result && t->scc_root == NULL )
+ {
+ t->scc_root = rescanning;
+ rescanning->depends = targetentry( rescanning->depends, t );
+ }
+ return result;
+}
+
+
 /*
  * make0() - bind and scan everything to make a TARGET.
  *
@@ -253,58 +273,64 @@
     TARGET * p, /* parent */
     int depth, /* for display purposes */
     COUNTS * counts, /* for reporting */
- int anyhow
+ int anyhow,
+ TARGET * rescanning
 ) /* forcibly touch all (real) targets */
 {
     TARGETS * c;
     TARGET * ptime = t;
- time_t last;
- time_t leaf;
- time_t hlast;
+ TARGET * located_target = 0;
+ timestamp last;
+ timestamp leaf;
+ timestamp hlast;
     int fate;
     char const * flag = "";
     SETTINGS * s;
 
 #ifdef OPT_GRAPH_DEBUG_EXT
- int savedFate, oldTimeStamp;
+ int savedFate;
+ int oldTimeStamp;
 #endif
 
     if ( DEBUG_MAKEPROG )
         printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
 
     /*
- * Step 1: initialize
+ * Step 1: Initialize.
      */
 
     if ( DEBUG_MAKEPROG )
         printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
 
     t->fate = T_FATE_MAKING;
+ t->depth = depth;
 
     /*
- * Step 2: under the influence of "on target" variables,
- * bind the target and search for headers.
+ * Step 2: Under the influence of "on target" variables, bind the target and
+ * search for headers.
      */
 
- /* Step 2a: set "on target" variables. */
+ /* Step 2a: Set "on target" variables. */
     s = copysettings( t->settings );
     pushsettings( root_module(), s );
 
- /* Step 2b: find and timestamp the target file (if it is a file). */
+ /* Step 2b: Find and timestamp the target file (if it is a file). */
     if ( ( t->binding == T_BIND_UNBOUND ) && !( t->flags & T_FLAG_NOTFILE ) )
     {
         OBJECT * another_target;
         object_free( t->boundname );
         t->boundname = search( t->name, &t->time, &another_target,
- t->flags & T_FLAG_ISFILE );
+ t->flags & T_FLAG_ISFILE );
         /* If it was detected that this target refers to an already existing and
- * bound one, we add an include dependency, so that every target
- * depending on us will depend on that other target as well.
+ * bound target, we add a dependency so that every target depending on
+ * us will depend on that other target as well.
          */
         if ( another_target )
- target_include( t, bindtarget( another_target ) );
+ located_target = bindtarget( another_target );
 
- t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
+ t->binding = timestamp_empty( &t->time )
+ ? T_BIND_MISSING
+ : T_BIND_EXISTS;
     }
 
     /* INTERNAL, NOTFILE header nodes have the time of their parents. */
@@ -325,7 +351,7 @@
         LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
         if ( !list_empty( var ) )
         {
- TARGET * semaphore = bindtarget( list_front( var ) );
+ TARGET * const semaphore = bindtarget( list_front( var ) );
             semaphore->progress = T_MAKE_SEMAPHORE;
             t->semaphore = semaphore;
         }
@@ -341,54 +367,69 @@
     freesettings( s );
 
     /*
- * Pause for a little progress reporting .
+ * Pause for a little progress reporting.
      */
 
     if ( DEBUG_BIND )
     {
- if ( ! object_equal( t->name, t->boundname ) )
- printf( "bind\t--\t%s%s: %s\n",
- spaces( depth ), object_str( t->name ), object_str( t->boundname ) );
+ if ( !object_equal( t->name, t->boundname ) )
+ printf( "bind\t--\t%s%s: %s\n", spaces( depth ),
+ object_str( t->name ), object_str( t->boundname ) );
 
         switch ( t->binding )
         {
         case T_BIND_UNBOUND:
         case T_BIND_MISSING:
         case T_BIND_PARENTS:
- printf( "time\t--\t%s%s: %s\n",
- spaces( depth ), object_str( t->name ), target_bind[ (int) t->binding ] );
+ printf( "time\t--\t%s%s: %s\n", spaces( depth ),
+ object_str( t->name ), target_bind[ (int)t->binding ] );
             break;
 
         case T_BIND_EXISTS:
- printf( "time\t--\t%s%s: %s",
- spaces( depth ), object_str( t->name ), ctime( &t->time ) );
+ printf( "time\t--\t%s%s: %s\n", spaces( depth ),
+ object_str( t->name ), timestamp_str( &t->time ) );
             break;
         }
     }
 
     /*
- * Step 3: recursively make0() dependencies & headers.
+ * Step 3: Recursively make0() dependencies & headers.
      */
 
- /* Step 3a: recursively make0() dependencies. */
+ /* Step 3a: Recursively make0() dependencies. */
     for ( c = t->depends; c; c = c->next )
     {
- int internal = t->flags & T_FLAG_INTERNAL;
+ int const internal = t->flags & T_FLAG_INTERNAL;
 
         /* Warn about circular deps, except for includes, which include each
          * other alot.
          */
         if ( c->target->fate == T_FATE_INIT )
- make0( c->target, ptime, depth + 1, counts, anyhow );
+ make0( c->target, ptime, depth + 1, counts, anyhow, rescanning );
         else if ( c->target->fate == T_FATE_MAKING && !internal )
- printf( "warning: %s depends on itself\n", object_str( c->target->name ) );
+ printf( "warning: %s depends on itself\n", object_str(
+ c->target->name ) );
+ else if ( c->target->fate != T_FATE_MAKING && rescanning )
+ make0rescan( c->target, rescanning );
+ if ( rescanning && c->target->includes && c->target->includes->fate !=
+ T_FATE_MAKING )
+ make0rescan( target_scc( c->target->includes ), rescanning );
     }
 
- /* Step 3b: recursively make0() internal includes node. */
+ if ( located_target )
+ {
+ if ( located_target->fate == T_FATE_INIT )
+ make0( located_target, ptime, depth + 1, counts, anyhow, rescanning
+ );
+ else if ( located_target->fate != T_FATE_MAKING && rescanning )
+ make0rescan( located_target, rescanning );
+ }
+
+ /* Step 3b: Recursively make0() internal includes node. */
     if ( t->includes )
- make0( t->includes, p, depth + 1, counts, anyhow );
+ make0( t->includes, p, depth + 1, counts, anyhow, rescanning );
 
- /* Step 3c: add dependencies' includes to our direct dependencies. */
+ /* Step 3c: Add dependencies' includes to our direct dependencies. */
     {
         TARGETS * incs = 0;
         for ( c = t->depends; c; c = c->next )
@@ -397,47 +438,86 @@
         t->depends = targetchain( t->depends, incs );
     }
 
+ if ( located_target )
+ t->depends = targetentry( t->depends, located_target );
+
+ /* Step 3d: Detect cycles. */
+ {
+ int cycle_depth = depth;
+ for ( c = t->depends; c; c = c->next )
+ {
+ TARGET * scc_root = target_scc( c->target );
+ if ( scc_root->fate == T_FATE_MAKING &&
+ ( !scc_root->includes ||
+ scc_root->includes->fate != T_FATE_MAKING ) )
+ {
+ if ( scc_root->depth < cycle_depth )
+ {
+ cycle_depth = scc_root->depth;
+ t->scc_root = scc_root;
+ }
+ }
+ }
+ }
+
     /*
- * Step 4: compute time & fate
+ * Step 4: Compute time & fate.
      */
 
- /* Step 4a: pick up dependencies' time and fate */
- last = 0;
- leaf = 0;
+ /* Step 4a: Pick up dependencies' time and fate. */
+ timestamp_clear( &last );
+ timestamp_clear( &leaf );
     fate = T_FATE_STABLE;
     for ( c = t->depends; c; c = c->next )
     {
+ /* If we are in a different strongly connected component, pull
+ * timestamps from the root.
+ */
+ if ( c->target->scc_root )
+ {
+ TARGET * const scc_root = target_scc( c->target );
+ if ( scc_root != t->scc_root )
+ {
+ timestamp_max( &c->target->leaf, &c->target->leaf,
+ &scc_root->leaf );
+ timestamp_max( &c->target->time, &c->target->time,
+ &scc_root->time );
+ c->target->fate = max( c->target->fate, scc_root->fate );
+ }
+ }
+
         /* If LEAVES has been applied, we only heed the timestamps of the leaf
          * source nodes.
          */
- leaf = max( leaf, c->target->leaf );
-
+ timestamp_max( &leaf, &leaf, &c->target->leaf );
         if ( t->flags & T_FLAG_LEAVES )
         {
- last = leaf;
+ timestamp_copy( &last, &leaf );
             continue;
         }
-
- last = max( last, c->target->time );
+ timestamp_max( &last, &last, &c->target->time );
         fate = max( fate, c->target->fate );
 
 #ifdef OPT_GRAPH_DEBUG_EXT
         if ( DEBUG_FATE )
             if ( fate < c->target->fate )
                 printf( "fate change %s from %s to %s by dependency %s\n",
- object_str( t->name ), target_fate[(int) fate], target_fate[(int) c->target->fate],
- object_str( c->target->name ) );
+ object_str( t->name ), target_fate[ (int)fate ],
+ target_fate[ (int)c->target->fate ], object_str(
+ c->target->name ) );
 #endif
     }
 
- /* Step 4b: pick up included headers time */
+ /* Step 4b: Pick up included headers time. */
 
     /*
- * If a header is newer than a temp source that includes it,
- * the temp source will need building.
+ * If a header is newer than a temp source that includes it, the temp source
+ * will need building.
      */
-
- hlast = t->includes ? t->includes->time : 0;
+ if ( t->includes )
+ timestamp_copy( &hlast, &t->includes->time );
+ else
+ timestamp_clear( &hlast );
 
     /* Step 4c: handle NOUPDATE oddity.
      *
@@ -454,8 +534,8 @@
                     object_str( t->name ) );
 #endif
 
- last = 0;
- t->time = 0;
+ timestamp_clear( &last );
+ timestamp_clear( &t->time );
 
         /* Do not inherit our fate from our dependencies. Decide fate based only
          * upon other flags and our binding (done later).
@@ -463,7 +543,7 @@
         fate = T_FATE_STABLE;
     }
 
- /* Step 4d: determine fate: rebuild target or what? */
+ /* Step 4d: Determine fate: rebuild target or what? */
 
     /*
         In English:
@@ -478,9 +558,8 @@
         If target newer than non-notfile parent, mark target newer.
         Otherwise, stable!
 
- Note this block runs from least to most stable:
- as we make it further down the list, the target's
- fate is getting stabler.
+ Note this block runs from least to most stable: as we make it further
+ down the list, the target's fate gets more stable.
     */
 
 #ifdef OPT_GRAPH_DEBUG_EXT
@@ -500,21 +579,24 @@
     {
         fate = T_FATE_MISSING;
     }
- else if ( ( t->binding == T_BIND_EXISTS ) && ( last > t->time ) )
+ else if ( t->binding == T_BIND_EXISTS && timestamp_cmp( &last, &t->time ) >
+ 0 )
     {
 #ifdef OPT_GRAPH_DEBUG_EXT
         oldTimeStamp = 1;
 #endif
         fate = T_FATE_OUTDATED;
     }
- else if ( ( t->binding == T_BIND_PARENTS ) && ( last > p->time ) )
+ else if ( t->binding == T_BIND_PARENTS && timestamp_cmp( &last, &p->time ) >
+ 0 )
     {
 #ifdef OPT_GRAPH_DEBUG_EXT
         oldTimeStamp = 1;
 #endif
         fate = T_FATE_NEEDTMP;
     }
- else if ( ( t->binding == T_BIND_PARENTS ) && ( hlast > p->time ) )
+ else if ( t->binding == T_BIND_PARENTS && timestamp_cmp( &hlast, &p->time )
+ > 0 )
     {
         fate = T_FATE_NEEDTMP;
     }
@@ -526,12 +608,12 @@
     {
         fate = T_FATE_TOUCHED;
     }
- else if ( ( t->binding == T_BIND_EXISTS ) && ( t->flags & T_FLAG_TEMP ) )
+ else if ( t->binding == T_BIND_EXISTS && ( t->flags & T_FLAG_TEMP ) )
     {
         fate = T_FATE_ISTMP;
     }
- else if ( ( t->binding == T_BIND_EXISTS ) && p &&
- ( p->binding != T_BIND_UNBOUND ) && ( t->time > p->time ) )
+ else if ( t->binding == T_BIND_EXISTS && p && p->binding != T_BIND_UNBOUND
+ && timestamp_cmp( &t->time, &p->time ) > 0 )
     {
 #ifdef OPT_GRAPH_DEBUG_EXT
         oldTimeStamp = 1;
@@ -550,12 +632,12 @@
                 target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
         else
             printf( "fate change %s from %s to %s%s\n", object_str( t->name ),
- target_fate[ savedFate ], target_fate[ fate ],
- oldTimeStamp ? " (by timestamp)" : "" );
+ target_fate[ savedFate ], target_fate[ fate ], oldTimeStamp ?
+ " (by timestamp)" : "" );
         }
 #endif
 
- /* Step 4e: handle missing files */
+ /* Step 4e: Handle missing files. */
     /* If it is missing and there are no actions to create it, boom. */
     /* If we can not make a target we do not care about it, okay. */
     /* We could insist that there are updating actions for all missing */
@@ -580,11 +662,11 @@
         }
     }
 
- /* Step 4f: propagate dependencies' time & fate. */
+ /* Step 4f: Propagate dependencies' time & fate. */
     /* Set leaf time to be our time only if this is a leaf. */
 
- t->time = max( t->time, last );
- t->leaf = leaf ? leaf : t->time ;
+ timestamp_max( &t->time, &t->time, &last );
+ timestamp_copy( &t->leaf, timestamp_empty( &leaf ) ? &t->time : &leaf );
     /* This target's fate may have been updated by virtue of following some
      * target's rebuilds list, so only allow it to be increased to the fate we
      * have calculated. Otherwise, grab its new fate.
@@ -594,21 +676,21 @@
     else
         fate = t->fate;
 
- /* Step 4g: if this target needs to be built, force rebuild everything in
- * this target's rebuilds list.
+ /* Step 4g: If this target needs to be built, force rebuild everything in
+ * its rebuilds list.
      */
     if ( ( fate >= T_FATE_BUILD ) && ( fate < T_FATE_BROKEN ) )
         force_rebuilds( t );
 
     /*
- * Step 5: sort dependencies by their update time.
+ * Step 5: Sort dependencies by their update time.
      */
 
     if ( globs.newestfirst )
         t->depends = make0sort( t->depends );
 
     /*
- * Step 6: a little harmless tabulating for tracing purposes
+ * Step 6: A little harmless tabulating for tracing purposes.
      */
 
     /* Do not count or report interal includes nodes. */
@@ -621,7 +703,10 @@
         ++counts->targets;
 #else
         if ( !( ++counts->targets % 1000 ) && DEBUG_MAKE )
+ {
             printf( "...patience...\n" );
+ fflush(stdout);
+ }
 #endif
 
         if ( fate == T_FATE_ISTMP )
@@ -637,18 +722,19 @@
 
     if ( !( t->flags & T_FLAG_NOTFILE ) && ( fate >= T_FATE_SPOIL ) )
         flag = "+";
- else if ( ( t->binding == T_BIND_EXISTS ) && p && ( t->time > p->time ) )
+ else if ( t->binding == T_BIND_EXISTS && p && timestamp_cmp( &t->time,
+ &p->time ) > 0 )
         flag = "*";
 
     if ( DEBUG_MAKEPROG )
- printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int) t->fate ],
+ printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int)t->fate ],
             spaces( depth ), object_str( t->name ) );
 }
 
 
 #ifdef OPT_GRAPH_DEBUG_EXT
 
-static const char * target_name( TARGET * t )
+static char const * target_name( TARGET * t )
 {
     static char buf[ 1000 ];
     if ( t->flags & T_FLAG_INTERNAL )
@@ -675,19 +761,22 @@
 
     switch ( t->fate )
     {
- case T_FATE_TOUCHED:
- case T_FATE_MISSING:
- case T_FATE_OUTDATED:
- case T_FATE_UPDATE:
- printf( "->%s%2d Name: %s\n", spaces( depth ), depth, target_name( t ) );
- break;
- default:
- printf( " %s%2d Name: %s\n", spaces( depth ), depth, target_name( t ) );
- break;
+ case T_FATE_TOUCHED:
+ case T_FATE_MISSING:
+ case T_FATE_OUTDATED:
+ case T_FATE_UPDATE:
+ printf( "->%s%2d Name: %s\n", spaces( depth ), depth, target_name( t
+ ) );
+ break;
+ default:
+ printf( " %s%2d Name: %s\n", spaces( depth ), depth, target_name( t
+ ) );
+ break;
     }
 
- if ( ! object_equal( t->name, t->boundname ) )
- printf( " %s Loc: %s\n", spaces( depth ), object_str( t->boundname ) );
+ if ( !object_equal( t->name, t->boundname ) )
+ printf( " %s Loc: %s\n", spaces( depth ), object_str( t->boundname )
+ );
 
     switch ( t->fate )
     {
@@ -701,7 +790,8 @@
         printf( " %s : Up to date temp file\n", spaces( depth ) );
         break;
     case T_FATE_NEEDTMP:
- printf( " %s : Temporary file, to be updated\n", spaces( depth ) );
+ printf( " %s : Temporary file, to be updated\n", spaces( depth )
+ );
         break;
     case T_FATE_TOUCHED:
         printf( " %s : Been touched, updating it\n", spaces( depth ) );
@@ -741,8 +831,8 @@
     for ( c = t->depends; c; c = c->next )
     {
         printf( " %s : Depends on %s (%s)", spaces( depth ),
- target_name( c->target ), target_fate[ (int) c->target->fate ] );
- if ( c->target->time == t->time )
+ target_name( c->target ), target_fate[ (int)c->target->fate ] );
+ if ( !timestamp_cmp( &c->target->time, &t->time ) )
             printf( " (max time)");
         printf( "\n" );
     }
@@ -778,12 +868,10 @@
         chain = chain->next;
 
         /* Find point s in result for c. */
- while ( s && ( s->target->time > c->target->time ) )
+ while ( s && timestamp_cmp( &s->target->time, &c->target->time ) > 0 )
             s = s->next;
 
- /* Insert c in front of s (might be 0). Do not even think of deciphering
- * this.
- */
+ /* Insert c in front of s (might be 0). */
         c->next = s; /* good even if s = 0 */
         if ( result == s ) result = c; /* new head of chain? */
         if ( !s ) s = result; /* wrap to ensure a next */
@@ -802,7 +890,8 @@
 
 void mark_target_for_updating( OBJECT * target )
 {
- targets_to_update_ = list_push_back( targets_to_update_, object_copy( target ) );
+ targets_to_update_ = list_push_back( targets_to_update_, object_copy(
+ target ) );
 }
 
 

Modified: branches/release/tools/build/v2/engine/make.h
==============================================================================
--- branches/release/tools/build/v2/engine/make.h (original)
+++ branches/release/tools/build/v2/engine/make.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -13,9 +13,10 @@
 
 #include "lists.h"
 #include "object.h"
+#include "rules.h"
 
 int make( LIST * targets, int anyhow );
-int make1( TARGET * t );
+int make1( LIST * t );
 
 typedef struct {
     int temp;
@@ -27,21 +28,17 @@
 } COUNTS ;
 
 
-void make0( TARGET *t, TARGET *p, int depth,
- COUNTS *counts, int anyhow );
+void make0( TARGET * t, TARGET * p, int depth, COUNTS * counts, int anyhow,
+ TARGET * rescanning );
 
 
-/*
- * Specifies that the target should be updated.
- */
+/* Specifies that the target should be updated. */
 void mark_target_for_updating( OBJECT * target );
-/*
- * Returns the list of all the target previously passed to 'mark_target_for_updating'.
- */
+
+/* Returns targets previously passed to mark_target_for_updating(). */
 LIST * targets_to_update();
-/*
- * Cleasr/unmarks all targets that are currently marked for update.
- */
+
+/* Clears/unmarks all targets currently marked for update. */
 void clear_targets_to_update();
 
 #endif

Modified: branches/release/tools/build/v2/engine/make1.c
==============================================================================
--- branches/release/tools/build/v2/engine/make1.c (original)
+++ branches/release/tools/build/v2/engine/make1.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,69 +11,58 @@
  */
 
 /*
- * make1.c - execute command to bring targets up to date
+ * make1.c - execute commands to bring targets up to date
  *
- * This module contains make1(), the entry point called by make() to
- * recursively decend the dependency graph executing update actions as
- * marked by make0().
+ * This module contains make1(), the entry point called by make() to recursively
+ * descend the dependency graph executing update actions as marked by make0().
  *
  * External routines:
- *
- * make1() - execute commands to update a TARGET and all of its dependencies.
+ * make1() - execute commands to update a TARGET and all of its dependencies
  *
  * Internal routines, the recursive/asynchronous command executors:
- *
- * make1a() - recursively traverse dependency target tree, calling make1b().
- * make1atail() - started processing all dependencies so go on to make1b().
- * make1b() - when dependencies are up to date, build target with make1c().
- * make1c() - launch target's next command, call parents' make1b() if none.
- * make1d() - handle command execution completion and call back make1c().
+ * make1a() - recursively schedules dependency builds and then goes to
+ * MAKE1B
+ * make1b() - if nothing is blocking this target's build, proceed to
+ * MAKE1C
+ * make1c() - launch target's next command, or go to parents' MAKE1B
+ * if none
+ * make1c_closure() - handle command execution completion and go to MAKE1C
  *
  * Internal support routines:
- *
- * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc.
- * make1list() - turn a list of targets into a LIST, for $(<) and $(>).
- * make1settings() - for vars that get bound values, build up replacement lists.
- * make1bind() - bind targets that weren't bound in dependency analysis.
- *
- * 04/16/94 (seiwald) - Split from make.c.
- * 04/21/94 (seiwald) - Handle empty "updated" actions.
- * 05/04/94 (seiwald) - async multiprocess (-j) support.
- * 06/01/94 (seiwald) - new 'actions existing' does existing sources.
- * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
- * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
- * 01/22/94 (seiwald) - pass per-target JAMSHELL down to exec_cmd().
- * 02/28/95 (seiwald) - Handle empty "existing" actions.
- * 03/10/95 (seiwald) - Fancy counts.
+ * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc.
+ * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
+ * make1settings() - for vars with bound values, build up replacement lists
+ * make1bind() - bind targets that weren't bound in dependency analysis
  */
 
 #include "jam.h"
+#include "make.h"
 
+#include "command.h"
+#include "compile.h"
+#include "execcmd.h"
+#include "headers.h"
 #include "lists.h"
+#include "object.h"
+#include "output.h"
 #include "parse.h"
-#include "assert.h"
-#include "variable.h"
 #include "rules.h"
-#include "headers.h"
-
 #include "search.h"
-#include "object.h"
-#include "make.h"
-#include "command.h"
-#include "execcmd.h"
-#include "compile.h"
-#include "output.h"
+#include "variable.h"
 
+#include <assert.h>
 #include <stdlib.h>
 
-#if ! defined(NT) || defined(__GNUC__)
+#if !defined( NT ) || defined( __GNUC__ )
     #include <unistd.h> /* for unlink */
 #endif
 
-static CMD * make1cmds ( TARGET * );
-static LIST * make1list ( LIST *, TARGETS *, int flags );
-static SETTINGS * make1settings( struct module_t * module, LIST * vars );
-static void make1bind ( TARGET * );
+static CMD * make1cmds ( TARGET * );
+static LIST * make1list ( LIST *, TARGETS *, int flags );
+static SETTINGS * make1settings ( struct module_t *, LIST * vars );
+static void make1bind ( TARGET * );
+static TARGET * make1findcycle ( TARGET * );
+static void make1breakcycle( TARGET *, TARGET * cycle_root );
 
 /* Ugly static - it is too hard to carry it through the callbacks. */
 
@@ -83,31 +72,29 @@
     int skipped;
     int total;
     int made;
-} counts[ 1 ] ;
+} counts[ 1 ];
 
-/* Target state - remove recursive calls by just keeping track of state target
- * is in.
- */
-typedef struct _state
-{
- struct _state * prev; /* previous state on stack */
- TARGET * t; /* current target */
- TARGET * parent; /* parent argument necessary for make1a() */
-#define T_STATE_MAKE1A 0 /* make1a() should be called */
-#define T_STATE_MAKE1ATAIL 1 /* make1atail() should be called */
-#define T_STATE_MAKE1B 2 /* make1b() should be called */
-#define T_STATE_MAKE1C 3 /* make1c() should be called */
-#define T_STATE_MAKE1D 4 /* make1d() should be called */
- int curstate; /* current state */
- int status;
-} state;
-
-static void make1a ( state * );
-static void make1atail ( state * );
-static void make1b ( state * );
-static void make1c ( state * );
-static void make1d ( state * );
-static void make_closure( void * closure, int status, timing_info *, const char *, const char * );
+/* Target state. */
+#define T_STATE_MAKE1A 0 /* make1a() should be called */
+#define T_STATE_MAKE1B 1 /* make1b() should be called */
+#define T_STATE_MAKE1C 2 /* make1c() should be called */
+
+typedef struct _state state;
+struct _state
+{
+ state * prev; /* previous state on stack */
+ TARGET * t; /* current target */
+ TARGET * parent; /* parent argument necessary for MAKE1A */
+ int curstate; /* current state */
+};
+
+static void make1a( state * const );
+static void make1b( state * const );
+static void make1c( state const * const );
+
+static void make1c_closure( void * const closure, int status,
+ timing_info const * const, char const * const cmd_stdout,
+ char const * const cmd_stderr, int const cmd_exit_reason );
 
 typedef struct _stack
 {
@@ -118,22 +105,24 @@
 
 static state * state_freelist = NULL;
 
+/* Currently running command counter. */
+static int cmdsrunning;
+
 
 static state * alloc_state()
 {
- if ( state_freelist != NULL )
+ if ( state_freelist )
     {
- state * pState = state_freelist;
+ state * const pState = state_freelist;
         state_freelist = pState->prev;
         memset( pState, 0, sizeof( state ) );
         return pState;
     }
-
     return (state *)BJAM_MALLOC( sizeof( state ) );
 }
 
 
-static void free_state( state * pState )
+static void free_state( state * const pState )
 {
     pState->prev = state_freelist;
     state_freelist = pState;
@@ -142,44 +131,41 @@
 
 static void clear_state_freelist()
 {
- while ( state_freelist != NULL )
+ while ( state_freelist )
     {
- state * pState = state_freelist;
+ state * const pState = state_freelist;
         state_freelist = state_freelist->prev;
         BJAM_FREE( pState );
     }
 }
 
 
-static state * current_state( stack * pStack )
+static state * current_state( stack * const pStack )
 {
     return pStack->stack;
 }
 
 
-static void pop_state( stack * pStack )
+static void pop_state( stack * const pStack )
 {
- if ( pStack->stack != NULL )
+ if ( pStack->stack )
     {
- state * pState = pStack->stack->prev;
+ state * const pState = pStack->stack->prev;
         free_state( pStack->stack );
         pStack->stack = pState;
     }
 }
 
 
-static state * push_state( stack * pStack, TARGET * t, TARGET * parent, int curstate )
+static state * push_state( stack * const pStack, TARGET * const t,
+ TARGET * const parent, int const curstate )
 {
- state * pState = alloc_state();
-
+ state * const pState = alloc_state();
     pState->t = t;
     pState->parent = parent;
     pState->prev = pStack->stack;
     pState->curstate = curstate;
-
- pStack->stack = pState;
-
- return pStack->stack;
+ return pStack->stack = pState;
 }
 
 
@@ -187,12 +173,12 @@
  * Pushes a stack onto another stack, effectively reversing the order.
  */
 
-static void push_stack_on_stack( stack * pDest, stack * pSrc )
+static void push_stack_on_stack( stack * const pDest, stack * const pSrc )
 {
- while ( pSrc->stack != NULL )
+ while ( pSrc->stack )
     {
- state * pState = pSrc->stack;
- pSrc->stack = pSrc->stack->prev;
+ state * const pState = pSrc->stack;
+ pSrc->stack = pState->prev;
         pState->prev = pDest->stack;
         pDest->stack = pState;
     }
@@ -200,181 +186,203 @@
 
 
 /*
- * make1() - execute commands to update a TARGET and all of its dependencies.
+ * make1() - execute commands to update a list of targets and all of their dependencies
  */
 
 static int intr = 0;
+static int quit = 0;
 
-int make1( TARGET * t )
+int make1( LIST * targets )
 {
     state * pState;
+ int status = 0;
 
     memset( (char *)counts, 0, sizeof( *counts ) );
+
+ {
+ LISTITER iter, end;
+ stack temp_stack = { NULL };
+ for ( iter = list_begin( targets ), end = list_end( targets );
+ iter != end; iter = list_next( iter ) )
+ push_state( &temp_stack, bindtarget( list_item( iter ) ), NULL, T_STATE_MAKE1A );
+ push_stack_on_stack( &state_stack, &temp_stack );
+ }
+
+ /* Clear any state left over from the past */
+ quit = 0;
 
     /* Recursively make the target and its dependencies. */
- push_state( &state_stack, t, NULL, T_STATE_MAKE1A );
 
- do
+ while ( 1 )
     {
- while ( ( pState = current_state( &state_stack ) ) != NULL )
+ while ( ( pState = current_state( &state_stack ) ) )
         {
- if ( intr )
+ if ( quit )
                 pop_state( &state_stack );
 
             switch ( pState->curstate )
             {
- case T_STATE_MAKE1A : make1a ( pState ); break;
- case T_STATE_MAKE1ATAIL: make1atail( pState ); break;
- case T_STATE_MAKE1B : make1b ( pState ); break;
- case T_STATE_MAKE1C : make1c ( pState ); break;
- case T_STATE_MAKE1D : make1d ( pState ); break;
+ case T_STATE_MAKE1A: make1a( pState ); break;
+ case T_STATE_MAKE1B: make1b( pState ); break;
+ case T_STATE_MAKE1C: make1c( pState ); break;
+ default:
+ assert( !"make1(): Invalid state detected." );
             }
         }
+ if ( !cmdsrunning )
+ break;
+ /* Wait for outstanding commands to finish running. */
+ exec_wait();
     }
- /* Wait for any outstanding commands to finish running. */
- while ( exec_wait() );
 
     clear_state_freelist();
 
     /* Talk about it. */
     if ( counts->failed )
         printf( "...failed updating %d target%s...\n", counts->failed,
- counts->failed > 1 ? "s" : "" );
+ counts->failed > 1 ? "s" : "" );
     if ( DEBUG_MAKE && counts->skipped )
         printf( "...skipped %d target%s...\n", counts->skipped,
- counts->skipped > 1 ? "s" : "" );
+ counts->skipped > 1 ? "s" : "" );
     if ( DEBUG_MAKE && counts->made )
         printf( "...updated %d target%s...\n", counts->made,
- counts->made > 1 ? "s" : "" );
+ counts->made > 1 ? "s" : "" );
+
+ /* If we were interrupted, exit now that all child processes
+ have finished. */
+ if ( intr )
+ exit( 1 );
 
- return counts->total != counts->made;
+ {
+ LISTITER iter, end;
+ for ( iter = list_begin( targets ), end = list_end( targets );
+ iter != end; iter = list_next( iter ) )
+ {
+ /* Check that the target was updated and that the
+ update succeeded. */
+ TARGET * t = bindtarget( list_item( iter ) );
+ if (t->progress == T_MAKE_DONE)
+ {
+ if (t->status != EXEC_CMD_OK)
+ status = 1;
+ }
+ else if ( ! ( t->progress == T_MAKE_NOEXEC_DONE && globs.noexec ) )
+ {
+ status = 1;
+ }
+ }
+ }
+ return status;
 }
 
 
 /*
- * make1a() - recursively traverse target tree, calling make1b().
+ * make1a() - recursively schedules dependency builds and then goes to MAKE1B
  *
  * Called to start processing a specified target. Does nothing if the target is
  * already being processed or otherwise starts processing all of its
- * dependencies. Once all of its dependencies have started being processed goes
- * on and calls make1b() (actually does that indirectly via a helper
- * make1atail() state).
+ * dependencies.
  */
 
-static void make1a( state * pState )
+static void make1a( state * const pState )
 {
     TARGET * t = pState->t;
- TARGETS * c;
+ TARGET * const scc_root = target_scc( t );
+
+ if ( !pState->parent || target_scc( pState->parent ) != scc_root )
+ pState->t = t = scc_root;
 
     /* If the parent is the first to try to build this target or this target is
- * in the make1c() quagmire, arrange for the parent to be notified when this
- * target is built.
+ * in the MAKE1C quagmire, arrange for the parent to be notified when this
+ * target has been built.
      */
- if ( pState->parent )
- switch ( pState->t->progress )
+ if ( pState->parent && t->progress <= T_MAKE_RUNNING )
+ {
+ TARGET * const parent_scc = target_scc( pState->parent );
+ if ( t != parent_scc )
         {
- case T_MAKE_INIT:
- case T_MAKE_ACTIVE:
- case T_MAKE_RUNNING:
- pState->t->parents = targetentry( pState->t->parents,
- pState->parent );
- ++pState->parent->asynccnt;
+ t->parents = targetentry( t->parents, parent_scc );
+ ++parent_scc->asynccnt;
         }
+ }
 
- /*
- * If the target has been previously updated with -n in
- * effect, and we're ignoring -n, update it for real.
+ /* If the target has been previously updated with -n in effect, and we are
+ * now ignoring -n, update it for real. E.g. if the UPDATE_NOW rule was
+ * called for it twice - first with the -n option and then without.
      */
- if ( !globs.noexec && pState->t->progress == T_MAKE_NOEXEC_DONE )
- {
- pState->t->progress = T_MAKE_INIT;
- }
+ if ( !globs.noexec && t->progress == T_MAKE_NOEXEC_DONE )
+ t->progress = T_MAKE_INIT;
 
     /* If this target is already being processed then do nothing. There is no
      * need to start processing the same target all over again.
      */
- if ( pState->t->progress != T_MAKE_INIT )
+ if ( t->progress != T_MAKE_INIT )
     {
         pop_state( &state_stack );
         return;
     }
 
- /* Asynccnt counts the dependencies preventing this target from proceeding
- * to make1b() for actual building. We start off with a count of 1 to
- * prevent anything from happening until we can notify all dependencies that
- * they are needed. This 1 is accounted for when we call make1b() ourselves,
- * below. Without this if a a dependency gets built before we finish
+ /* Guard against circular dependencies. */
+ t->progress = T_MAKE_ONSTACK;
+
+ /* 'asynccnt' counts the dependencies preventing this target from proceeding
+ * to MAKE1C for actual building. We start off with a count of 1 to prevent
+ * anything from happening until we can notify all dependencies that they
+ * are needed. This 1 is then accounted for when we enter MAKE1B ourselves,
+ * below. Without this if a dependency gets built before we finish
      * processing all of our other dependencies our build might be triggerred
      * prematurely.
      */
- pState->t->asynccnt = 1;
-
- /* Add header nodes created during the building process. */
- {
- TARGETS * inc = 0;
- for ( c = t->depends; c; c = c->next )
- if ( c->target->rescanned && c->target->includes )
- inc = targetentry( inc, c->target->includes );
- t->depends = targetchain( t->depends, inc );
- }
-
- /* Guard against circular dependencies. */
- pState->t->progress = T_MAKE_ONSTACK;
+ t->asynccnt = 1;
 
+ /* Push dependency build requests (to be executed in the natural order). */
     {
         stack temp_stack = { NULL };
- for ( c = t->depends; c && !intr; c = c->next )
- push_state( &temp_stack, c->target, pState->t, T_STATE_MAKE1A );
-
- /* Using stacks reverses the order of execution. Reverse it back. */
+ TARGETS * c;
+ for ( c = t->depends; c && !quit; c = c->next )
+ push_state( &temp_stack, c->target, t, T_STATE_MAKE1A );
         push_stack_on_stack( &state_stack, &temp_stack );
     }
 
- pState->curstate = T_STATE_MAKE1ATAIL;
-}
-
-
-/*
- * make1atail() - started processing all dependencies so go on to make1b().
- */
+ t->progress = T_MAKE_ACTIVE;
 
-static void make1atail( state * pState )
-{
- pState->t->progress = T_MAKE_ACTIVE;
- /* Now that all of our dependencies have bumped up our asynccnt we can
- * remove our own internal bump added to prevent this target from being
- * built before all of its dependencies start getting processed.
+ /* Once all of our dependencies have started getting processed we can move
+ * onto MAKE1B.
+ */
+ /* Implementation note:
+ * In theory this would be done by popping this state before pushing
+ * dependency target build requests but as a slight optimization we simply
+ * modify our current state and leave it on the stack instead.
      */
     pState->curstate = T_STATE_MAKE1B;
 }
 
 
 /*
- * make1b() - when dependencies are up to date, build target with make1c().
+ * make1b() - if nothing is blocking this target's build, proceed to MAKE1C
  *
- * Called after all dependencies have started being processed and after each of
- * them finishes its processing. The target actually goes on to getting built in
- * make1c() only after all of its dependencies have finished their processing.
+ * Called after something stops blocking this target's build, e.g. that all of
+ * its dependencies have started being processed, one of its dependencies has
+ * been built or a semaphore this target has been waiting for is free again.
  */
 
-static void make1b( state * pState )
+static void make1b( state * const pState )
 {
- TARGET * t = pState->t;
- TARGETS * c;
- TARGET * failed = 0;
- const char * failed_name = "dependencies";
+ TARGET * const t = pState->t;
+ TARGET * failed = 0;
+ char const * failed_name = "dependencies";
 
- /* If any dependencies are still outstanding, wait until they call make1b()
- * to signal their completion.
+ /* If any dependencies are still outstanding, wait until they signal their
+ * completion by pushing this same state for their parent targets.
      */
- if ( --pState->t->asynccnt )
+ if ( --t->asynccnt )
     {
         pop_state( &state_stack );
         return;
     }
 
     /* Try to aquire a semaphore. If it is locked, wait until the target that
- * locked it is built and signal completition.
+ * locked it is built and signals completition.
      */
 #ifdef OPT_SEMAPHORE
     if ( t->semaphore && t->semaphore->asynccnt )
@@ -393,67 +401,64 @@
 
     /* Now ready to build target 't', if dependencies built OK. */
 
- /* Collect status from dependencies. If -n was passed then
- * act as though all dependencies built correctly. The only
- * way they can fail is if UPDATE_NOW was called. If
- * the dependencies can't be found or we got an interrupt,
- * we can't get here.
+ /* Collect status from dependencies. If -n was passed then act as though all
+ * dependencies built correctly (the only way they can fail is if UPDATE_NOW
+ * was called). If the dependencies can not be found or we got an interrupt,
+ * we can not get here.
      */
     if ( !globs.noexec )
     {
+ TARGETS * c;
         for ( c = t->depends; c; c = c->next )
- if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
+ if ( c->target->status > t->status && !( c->target->flags &
+ T_FLAG_NOCARE ) )
             {
                 failed = c->target;
- pState->t->status = c->target->status;
+ t->status = c->target->status;
             }
     }
+
     /* If an internal header node failed to build, we want to output the target
      * that it failed on.
      */
     if ( failed )
- {
         failed_name = failed->flags & T_FLAG_INTERNAL
             ? failed->failed
             : object_str( failed->name );
- }
     t->failed = failed_name;
 
     /* If actions for building any of the dependencies have failed, bail.
      * Otherwise, execute all actions to make the current target.
      */
- if ( ( pState->t->status == EXEC_CMD_FAIL ) && pState->t->actions )
+ if ( ( t->status == EXEC_CMD_FAIL ) && t->actions )
     {
         ++counts->skipped;
- if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
+ if ( ( t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
         {
- if ( !unlink( object_str( pState->t->boundname ) ) )
- printf( "...removing outdated %s\n", object_str( pState->t->boundname ) );
+ if ( !unlink( object_str( t->boundname ) ) )
+ printf( "...removing outdated %s\n", object_str( t->boundname )
+ );
         }
         else
- printf( "...skipped %s for lack of %s...\n", object_str( pState->t->name ), failed_name );
+ printf( "...skipped %s for lack of %s...\n", object_str( t->name ),
+ failed_name );
     }
 
- if ( pState->t->status == EXEC_CMD_OK )
- switch ( pState->t->fate )
+ if ( t->status == EXEC_CMD_OK )
+ switch ( t->fate )
         {
- /* These are handled by the default case below now
- case T_FATE_INIT:
- case T_FATE_MAKING:
- */
-
         case T_FATE_STABLE:
         case T_FATE_NEWER:
             break;
 
         case T_FATE_CANTFIND:
         case T_FATE_CANTMAKE:
- pState->t->status = EXEC_CMD_FAIL;
+ t->status = EXEC_CMD_FAIL;
             break;
 
         case T_FATE_ISTMP:
             if ( DEBUG_MAKE )
- printf( "...using %s...\n", object_str( pState->t->name ) );
+ printf( "...using %s...\n", object_str( t->name ) );
             break;
 
         case T_FATE_TOUCHED:
@@ -462,186 +467,215 @@
         case T_FATE_OUTDATED:
         case T_FATE_UPDATE:
         case T_FATE_REBUILD:
- /* Prepare commands for executing actions scheduled for this target
- * and then schedule transfer to make1c() state to proceed with
- * executing the prepared commands. Commands have their embedded
- * variables automatically expanded, including making use of any "on
- * target" variables.
+ /* Prepare commands for executing actions scheduled for this target.
+ * Commands have their embedded variables automatically expanded,
+ * including making use of any "on target" variables.
              */
- if ( pState->t->actions )
+ if ( t->actions )
             {
                 ++counts->total;
                 if ( DEBUG_MAKE && !( counts->total % 100 ) )
                     printf( "...on %dth target...\n", counts->total );
 
- pState->t->cmds = (char *)make1cmds( pState->t );
- /* Set the target's "progress" so that make1c() counts it among
- * its successes/failures.
+ t->cmds = (char *)make1cmds( t );
+ /* Update the target's "progress" so MAKE1C processing counts it
+ * among its successes/failures.
                  */
- pState->t->progress = T_MAKE_RUNNING;
+ t->progress = T_MAKE_RUNNING;
             }
             break;
 
- /* All possible fates should have been accounted for by now. */
+ /* All valid fates should have been accounted for by now. */
         default:
- printf( "ERROR: %s has bad fate %d", object_str( pState->t->name ),
- pState->t->fate );
+ printf( "ERROR: %s has bad fate %d", object_str( t->name ),
+ t->fate );
             abort();
         }
 
- /* Call make1c() to begin the execution of the chain of commands needed to
- * build the target. If we are not going to build the target (due of
- * dependency failures or no commands needing to be run) the chain will be
- * empty and make1c() will directly signal the target's completion.
- */
-
 #ifdef OPT_SEMAPHORE
     /* If there is a semaphore, indicate that it is in use. */
- if ( pState->t->semaphore )
+ if ( t->semaphore )
     {
- ++pState->t->semaphore->asynccnt;
+ ++t->semaphore->asynccnt;
         if ( DEBUG_EXECCMD )
- printf( "SEM: %s now used by %s\n", object_str( pState->t->semaphore->name ),
- object_str( pState->t->name ) );
+ printf( "SEM: %s now used by %s\n", object_str( t->semaphore->name
+ ), object_str( t->name ) );
     }
 #endif
 
+ /* Proceed to MAKE1C to begin executing the chain of commands prepared for
+ * building the target. If we are not going to build the target (e.g. due to
+ * dependency failures or no commands needing to be run) the chain will be
+ * empty and MAKE1C processing will directly signal the target's completion.
+ */
+ /* Implementation note:
+ * Morfing the current state on the stack instead of popping it and
+ * pushing a new one is a slight optimization with no side-effects since we
+ * pushed no other states while processing this one.
+ */
     pState->curstate = T_STATE_MAKE1C;
 }
 
 
 /*
- * make1c() - launch target's next command, call parents' make1b() if none.
+ * make1c() - launch target's next command, or go to parents' MAKE1B if none
  *
  * If there are (more) commands to run to build this target (and we have not hit
- * an error running earlier comands) we launch the command using exec_cmd(). If
- * there are no more commands to run, we collect the status from all the actions
- * and report our completion to all the parents.
+ * an error running earlier comands) we launch the command using exec_cmd().
+ * Command execution signals its completion in exec_wait() by calling our
+ * make1c_closure() callback.
+ *
+ * If there are no more commands to run, we collect the status from all the
+ * actions and report our completion to all the parents.
  */
 
-static void make1c( state * pState )
+static void make1c( state const * const pState )
 {
- CMD * cmd = (CMD *)pState->t->cmds;
+ TARGET * const t = pState->t;
+ CMD * const cmd = (CMD *)t->cmds;
 
- if ( cmd && ( pState->t->status == EXEC_CMD_OK ) )
+ if ( cmd && t->status == EXEC_CMD_OK )
     {
- const char * rule_name = 0;
- const char * target = 0;
+ /* Pop state first in case something below (e.g. exec_cmd(), exec_wait()
+ * or make1c_closure()) pushes a new state. Note that we must not access
+ * the popped state data after this as the same stack node might have
+ * been reused internally for some newly pushed state.
+ */
+ pop_state( &state_stack );
 
- if ( DEBUG_MAKEQ ||
- ( !( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE ) )
- {
- rule_name = object_str( cmd->rule->name );
- target = object_str( list_front( lol_get( &cmd->args, 0 ) ) );
- if ( globs.noexec )
- out_action( rule_name, target, cmd->buf->value, "", "", EXIT_OK );
- }
+ /* Increment the jobs running counter. */
+ ++cmdsrunning;
 
- if ( globs.noexec )
+ /* Execute the actual build command or fake it if no-op. */
+ if ( globs.noexec || cmd->noop )
         {
- pState->curstate = T_STATE_MAKE1D;
- pState->status = EXEC_CMD_OK;
+ timing_info time_info = { 0 };
+ timestamp_current( &time_info.start );
+ timestamp_copy( &time_info.end, &time_info.start );
+ make1c_closure( t, EXEC_CMD_OK, &time_info, "", "", EXIT_OK );
         }
         else
         {
- /* Pop state first because exec_cmd() could push state. */
- pop_state( &state_stack );
- exec_cmd( cmd->buf->value, make_closure, pState->t, cmd->shell, rule_name,
- target );
+ exec_cmd( cmd->buf, make1c_closure, t, cmd->shell );
+
+ /* Wait until under the concurrent command count limit. */
+ /* FIXME: This wait could be skipped here and moved to just before
+ * trying to execute a command that would cross the command count
+ * limit. Note though that this might affect the order in which
+ * unrelated targets get built and would thus require that all
+ * affected Boost Build tests be updated.
+ */
+ assert( 0 < globs.jobs );
+ assert( globs.jobs <= MAXJOBS );
+ while ( cmdsrunning >= globs.jobs )
+ exec_wait();
         }
     }
     else
     {
- TARGETS * c;
         ACTIONS * actions;
 
         /* Collect status from actions, and distribute it as well. */
- for ( actions = pState->t->actions; actions; actions = actions->next )
- if ( actions->action->status > pState->t->status )
- pState->t->status = actions->action->status;
- for ( actions = pState->t->actions; actions; actions = actions->next )
- if ( pState->t->status > actions->action->status )
- actions->action->status = pState->t->status;
+ for ( actions = t->actions; actions; actions = actions->next )
+ if ( actions->action->status > t->status )
+ t->status = actions->action->status;
+ for ( actions = t->actions; actions; actions = actions->next )
+ if ( t->status > actions->action->status )
+ actions->action->status = t->status;
 
         /* Tally success/failure for those we tried to update. */
- if ( pState->t->progress == T_MAKE_RUNNING )
- switch ( pState->t->status )
+ if ( t->progress == T_MAKE_RUNNING )
+ switch ( t->status )
             {
- case EXEC_CMD_OK : ++counts->made ; break;
+ case EXEC_CMD_OK: ++counts->made; break;
                 case EXEC_CMD_FAIL: ++counts->failed; break;
             }
 
         /* Tell parents their dependency has been built. */
         {
+ TARGETS * c;
             stack temp_stack = { NULL };
- TARGET * t = pState->t;
             TARGET * additional_includes = NULL;
 
- if ( globs.noexec )
- t->progress = T_MAKE_NOEXEC_DONE;
- else
- t->progress = T_MAKE_DONE;
+ t->progress = globs.noexec ? T_MAKE_NOEXEC_DONE : T_MAKE_DONE;
 
             /* Target has been updated so rescan it for dependencies. */
- if ( ( t->fate >= T_FATE_MISSING ) &&
- ( t->status == EXEC_CMD_OK ) &&
- !t->rescanned )
+ if ( t->fate >= T_FATE_MISSING && t->status == EXEC_CMD_OK &&
+ !( t->flags & T_FLAG_INTERNAL ) )
             {
                 TARGET * saved_includes;
- TARGET * target_to_rescan = t;
                 SETTINGS * s;
 
- target_to_rescan->rescanned = 1;
-
- if ( target_to_rescan->flags & T_FLAG_INTERNAL )
- target_to_rescan = t->original_target;
+ t->rescanned = 1;
 
                 /* Clean current includes. */
- saved_includes = target_to_rescan->includes;
- target_to_rescan->includes = 0;
+ saved_includes = t->includes;
+ t->includes = 0;
 
- s = copysettings( target_to_rescan->settings );
+ s = copysettings( t->settings );
                 pushsettings( root_module(), s );
- headers( target_to_rescan );
+ headers( t );
                 popsettings( root_module(), s );
                 freesettings( s );
 
- if ( target_to_rescan->includes )
+ if ( t->includes )
                 {
- /* Link the old includes on to make sure that it gets
- * cleaned up correctly.
- */
- target_to_rescan->includes->includes = saved_includes;
- target_to_rescan->includes->rescanned = 1;
                     /* Tricky. The parents have already been processed, but they
                      * have not seen the internal node, because it was just
- * created. We need to make the calls to make1a() that would
- * have been made by the parents here, and also make sure
- * all unprocessed parents will pick up the includes. We
- * must make sure processing of the additional make1a()
- * invocations is done before make1b() which means this
- * target is built, otherwise the parent would be considered
- * built before this make1a() processing has even started.
+ * created. We need to:
+ * - push MAKE1A states that would have been pushed by the
+ * parents here
+ * - make sure all unprocessed parents will pick up the
+ * new includes
+ * - make sure processing the additional MAKE1A states is
+ * done before processing the MAKE1B state for our
+ * current target (which would mean this target has
+ * already been built), otherwise the parent would be
+ * considered built before the additional MAKE1A state
+ * processing even got a chance to start.
+ */
+ make0( t->includes, t->parents->target, 0, 0, 0, t->includes
+ );
+ /* Link the old includes on to make sure that it gets
+ * cleaned up correctly.
                      */
- make0( target_to_rescan->includes, target_to_rescan->parents->target, 0, 0, 0 );
- for ( c = target_to_rescan->parents; c; c = c->next )
+ t->includes->includes = saved_includes;
+ for ( c = t->dependants; c; c = c->next )
                         c->target->depends = targetentry( c->target->depends,
- target_to_rescan->includes );
+ t->includes );
                     /* Will be processed below. */
- additional_includes = target_to_rescan->includes;
+ additional_includes = t->includes;
                 }
                 else
                 {
- target_to_rescan->includes = saved_includes;
+ t->includes = saved_includes;
                 }
             }
 
             if ( additional_includes )
                 for ( c = t->parents; c; c = c->next )
- push_state( &temp_stack, additional_includes, c->target, T_STATE_MAKE1A );
+ push_state( &temp_stack, additional_includes, c->target,
+ T_STATE_MAKE1A );
 
- for ( c = t->parents; c; c = c->next )
- push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
+ if ( t->scc_root )
+ {
+ TARGET * const scc_root = target_scc( t );
+ assert( scc_root->progress < T_MAKE_DONE );
+ for ( c = t->parents; c; c = c->next )
+ {
+ if ( target_scc( c->target ) == scc_root )
+ push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B
+ );
+ else
+ scc_root->parents = targetentry( scc_root->parents,
+ c->target );
+ }
+ }
+ else
+ {
+ for ( c = t->parents; c; c = c->next )
+ push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
+ }
 
 #ifdef OPT_SEMAPHORE
             /* If there is a semaphore, it is now free. */
@@ -651,22 +685,25 @@
                 --t->semaphore->asynccnt;
 
                 if ( DEBUG_EXECCMD )
- printf( "SEM: %s is now free\n", object_str( t->semaphore->name ) );
+ printf( "SEM: %s is now free\n", object_str(
+ t->semaphore->name ) );
 
                 /* If anything is waiting, notify the next target. There is no
- * point in notifying waiting targets, since they will be
+ * point in notifying all waiting targets, since they will be
                  * notified again.
                  */
                 if ( t->semaphore->parents )
                 {
                     TARGETS * first = t->semaphore->parents;
+ t->semaphore->parents = first->next;
                     if ( first->next )
                         first->next->tail = first->tail;
- t->semaphore->parents = first->next;
 
                     if ( DEBUG_EXECCMD )
- printf( "SEM: placing %s on stack\n", object_str( first->target->name ) );
- push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B );
+ printf( "SEM: placing %s on stack\n", object_str(
+ first->target->name ) );
+ push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B
+ );
                     BJAM_FREE( first );
                 }
             }
@@ -688,7 +725,7 @@
  * timing_info.
  */
 
-static void call_timing_rule( TARGET * target, timing_info * time )
+static void call_timing_rule( TARGET * target, timing_info const * const time )
 {
     LIST * timing_rule;
 
@@ -702,23 +739,25 @@
 
         /* Prepare the argument list. */
         FRAME frame[ 1 ];
+ OBJECT * rulename = list_front( timing_rule );
         frame_init( frame );
 
         /* args * :: $(__TIMING_RULE__[2-]) */
- lol_add( frame->args, list_copy_range( timing_rule, list_next( list_begin( timing_rule ) ), list_end( timing_rule ) ) );
+ lol_add( frame->args, list_copy_range( timing_rule, list_next(
+ list_begin( timing_rule ) ), list_end( timing_rule ) ) );
 
         /* target :: the name of the target */
         lol_add( frame->args, list_new( object_copy( target->name ) ) );
 
         /* start end user system :: info about the action command */
         lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_new(
- outf_time ( time->start ) ),
- outf_time ( time->end ) ),
- outf_double( time->user ) ),
+ outf_time( &time->start ) ),
+ outf_time( &time->end ) ),
+ outf_double( time->user ) ),
             outf_double( time->system ) ) );
 
         /* Call the rule. */
- evaluate_rule( list_front( timing_rule ), frame );
+ evaluate_rule( bindrule( rulename , root_module() ), rulename, frame );
 
         /* Clean up. */
         frame_free( frame );
@@ -734,14 +773,14 @@
 
 static void call_action_rule
 (
- TARGET * target,
- int status,
- timing_info * time,
- const char * executed_command,
- const char * command_output
+ TARGET * target,
+ int status,
+ timing_info const * time,
+ char const * executed_command,
+ char const * command_output
 )
 {
- LIST * action_rule;
+ LIST * action_rule;
 
     pushsettings( root_module(), target->settings );
     action_rule = var_get( root_module(), constant_ACTION_RULE );
@@ -757,21 +796,24 @@
 
         /* Prepare the argument list. */
         FRAME frame[ 1 ];
+ OBJECT * rulename = list_front( action_rule );
         frame_init( frame );
 
         /* args * :: $(__ACTION_RULE__[2-]) */
- lol_add( frame->args, list_copy_range( action_rule, list_next( list_begin( action_rule ) ), list_end( action_rule ) ) );
+ lol_add( frame->args, list_copy_range( action_rule, list_next(
+ list_begin( action_rule ) ), list_end( action_rule ) ) );
 
         /* target :: the name of the target */
         lol_add( frame->args, list_new( object_copy( target->name ) ) );
 
- /* command status start end user system :: info about the action command */
+ /* command status start end user system :: info about the action command
+ */
         lol_add( frame->args,
             list_push_back( list_push_back( list_push_back( list_push_back( list_push_back( list_new(
                 object_new( executed_command ) ),
                 outf_int( status ) ),
- outf_time( time->start ) ),
- outf_time( time->end ) ),
+ outf_time( &time->start ) ),
+ outf_time( &time->end ) ),
                 outf_double( time->user ) ),
                 outf_double( time->system ) ) );
 
@@ -782,7 +824,7 @@
             lol_add( frame->args, L0 );
 
         /* Call the rule. */
- evaluate_rule( list_front( action_rule ), frame );
+ evaluate_rule( bindrule( rulename, root_module() ), rulename, frame );
 
         /* Clean up. */
         frame_free( frame );
@@ -791,114 +833,130 @@
 
 
 /*
- * make_closure() - internal function passed as a notification callback for when
- * commands finish getting executed by the OS.
+ * make1c_closure() - handle command execution completion and go to MAKE1C.
+ *
+ * Internal function passed as a notification callback for when a command
+ * finishes getting executed by the OS or called directly when faking that a
+ * command had been executed by the OS.
+ *
+ * Now all we need to do is fiddle with the command exit status and push a new
+ * MAKE1C state to execute the next command scheduled for building this target
+ * or close up the target's build process in case there are no more commands
+ * scheduled for it. On interrupts, we bail heavily.
  */
 
-static void make_closure
+static void make1c_closure
 (
- void * closure,
- int status,
- timing_info * time,
- const char * executed_command,
- const char * command_output
+ void * const closure,
+ int status_orig,
+ timing_info const * const time,
+ char const * const cmd_stdout,
+ char const * const cmd_stderr,
+ int const cmd_exit_reason
 )
 {
- TARGET * built = (TARGET *)closure;
-
- call_timing_rule( built, time );
- if ( DEBUG_EXECCMD )
- printf( "%f sec system; %f sec user\n", time->system, time->user );
+ TARGET * const t = (TARGET *)closure;
+ CMD * const cmd = (CMD *)t->cmds;
+ char const * rule_name = 0;
+ char const * target_name = 0;
 
- call_action_rule( built, status, time, executed_command, command_output );
+ assert( cmd );
 
- push_state( &state_stack, built, NULL, T_STATE_MAKE1D )->status = status;
-}
+ --cmdsrunning;
 
+ /* Calculate the target's status from the cmd execution result. */
+ {
+ /* Store the target's status. */
+ t->status = status_orig;
 
-/*
- * make1d() - handle command execution completion and call back make1c().
- *
- * exec_cmd() has completed and now all we need to do is fiddle with the status
- * and call back to make1c() so it can run the next command scheduled for
- * building this target or close up the target's build process in case there are
- * no more commands scheduled for it. On interrupts, we bail heavily.
- */
+ /* Invert OK/FAIL target status when FAIL_EXPECTED has been applied. */
+ if ( t->flags & T_FLAG_FAIL_EXPECTED && !globs.noexec )
+ {
+ switch ( t->status )
+ {
+ case EXEC_CMD_FAIL: t->status = EXEC_CMD_OK; break;
+ case EXEC_CMD_OK: t->status = EXEC_CMD_FAIL; break;
+ }
+ }
 
-static void make1d( state * pState )
-{
- TARGET * t = pState->t;
- CMD * cmd = (CMD *)t->cmds;
- int status = pState->status;
+ /* Ignore failures for actions marked as 'ignore'. */
+ if ( t->status == EXEC_CMD_FAIL && cmd->rule->actions->flags &
+ RULE_IGNORE )
+ t->status = EXEC_CMD_OK;
+ }
 
- if ( t->flags & T_FLAG_FAIL_EXPECTED && !globs.noexec )
+ if ( DEBUG_MAKEQ ||
+ ( DEBUG_MAKE && !( cmd->rule->actions->flags & RULE_QUIETLY ) ) )
     {
- /* Invert execution result when FAIL_EXPECTED has been applied. */
- switch ( status )
- {
- case EXEC_CMD_FAIL: status = EXEC_CMD_OK ; break;
- case EXEC_CMD_OK: status = EXEC_CMD_FAIL; break;
- }
+ rule_name = object_str( cmd->rule->name );
+ target_name = object_str( list_front( lol_get( (LOL *)&cmd->args, 0 ) )
+ );
     }
 
- if ( ( status == EXEC_CMD_FAIL ) &&
- ( cmd->rule->actions->flags & RULE_IGNORE ) )
- status = EXEC_CMD_OK;
+ out_action( rule_name, target_name, cmd->buf->value, cmd_stdout, cmd_stderr,
+ cmd_exit_reason );
 
- /* On interrupt, set intr so _everything_ fails. */
- if ( status == EXEC_CMD_INTR )
- ++intr;
+ if ( !globs.noexec )
+ {
+ call_timing_rule( t, time );
+ if ( DEBUG_EXECCMD )
+ printf( "%f sec system; %f sec user\n", time->system, time->user );
+
+ /* Assume -p0 is in effect, i.e. cmd_stdout contains merged output. */
+ call_action_rule( t, status_orig, time, cmd->buf->value, cmd_stdout );
+ }
 
     /* Print command text on failure. */
- if ( ( status == EXEC_CMD_FAIL ) && DEBUG_MAKE )
+ if ( t->status == EXEC_CMD_FAIL && DEBUG_MAKE )
     {
         if ( !DEBUG_EXEC )
             printf( "%s\n", cmd->buf->value );
 
         printf( "...failed %s ", object_str( cmd->rule->name ) );
- list_print( lol_get( &cmd->args, 0 ) );
+ list_print( lol_get( (LOL *)&cmd->args, 0 ) );
         printf( "...\n" );
     }
 
- /* Treat failed commands as interrupts in case we were asked to stop the
- * build in case of any errors.
+ /* On interrupt, set quit so _everything_ fails. Do the same for failed
+ * commands if we were asked to stop the build in case of any errors.
      */
- if ( ( status == EXEC_CMD_FAIL ) && globs.quitquick )
+ if ( t->status == EXEC_CMD_INTR )
+ {
         ++intr;
+ ++quit;
+ }
+ if ( t->status == EXEC_CMD_FAIL && globs.quitquick )
+ ++quit;
 
- /* If the command was interrupted or failed and the target is not
- * "precious", remove the targets.
+ /* If the command was not successful remove all of its targets not marked as
+ * "precious".
      */
- if (status != EXEC_CMD_OK)
+ if ( t->status != EXEC_CMD_OK )
     {
- LIST * targets = lol_get( &cmd->args, 0 );
- LISTITER iter = list_begin( targets ), end = list_end( targets );
+ LIST * const targets = lol_get( (LOL *)&cmd->args, 0 );
+ LISTITER iter = list_begin( targets );
+ LISTITER const end = list_end( targets );
         for ( ; iter != end; iter = list_next( iter ) )
         {
- int need_unlink = 1;
- TARGET* t = bindtarget ( list_item( iter ) );
- if (t->flags & T_FLAG_PRECIOUS)
- {
- need_unlink = 0;
- }
- if (need_unlink && !unlink( object_str( list_item( iter ) ) ) )
- printf( "...removing %s\n", object_str( list_item( iter ) ) );
+ char const * const filename = object_str( list_item( iter ) );
+ TARGET const * const t = bindtarget( list_item( iter ) );
+ if ( !( t->flags & T_FLAG_PRECIOUS ) && !unlink( filename ) )
+ printf( "...removing %s\n", filename );
         }
     }
 
- /* Free this command and call make1c() to move onto the next one scheduled
- * for building this same target.
+ /* Free this command and push the MAKE1C state to execute the next one
+ * scheduled for building this same target.
      */
- t->status = status;
     t->cmds = (char *)cmd_next( cmd );
     cmd_free( cmd );
- pState->curstate = T_STATE_MAKE1C;
+ push_state( &state_stack, t, NULL, T_STATE_MAKE1C );
 }
 
 
 /*
  * swap_settings() - replace the settings from the current module and target
- * with those from the new module and target
+ * with those from the new module and target
  */
 
 static void swap_settings
@@ -909,7 +967,8 @@
     TARGET * new_target
 )
 {
- if ( ( new_target == *current_target ) && ( new_module == *current_module ) )
+ if ( ( new_target == *current_target ) &&
+ ( new_module == *current_module ) )
         return;
 
     if ( *current_target )
@@ -928,23 +987,25 @@
  *
  * Essentially copies a chain of ACTIONs to a chain of CMDs, grouping
  * RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions, and handling
- * RULE_NEWSRCS actions. The result is a chain of CMDs which can be expanded by
- * var_string() and executed using exec_cmd().
+ * RULE_NEWSRCS actions. The result is a chain of CMDs which has already had all
+ * of its embedded variable references expanded and can now be executed using
+ * exec_cmd().
  */
 
 static CMD * make1cmds( TARGET * t )
 {
- CMD * cmds = 0;
- LIST * shell = L0;
+ CMD * cmds = 0;
+ CMD * * cmds_next = &cmds;
+ LIST * shell = L0;
     module_t * settings_module = 0;
- TARGET * settings_target = 0;
- ACTIONS * a0;
- int running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
+ TARGET * settings_target = 0;
+ ACTIONS * a0;
+ int const running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING;
 
     /* Step through actions. Actions may be shared with other targets or grouped
      * using RULE_TOGETHER, so actions already seen are skipped.
      */
- for ( a0 = t->actions ; a0; a0 = a0->next )
+ for ( a0 = t->actions; a0; a0 = a0->next )
     {
         RULE * rule = a0->action->rule;
         rule_actions * actions = rule->actions;
@@ -952,9 +1013,6 @@
         LIST * nt;
         LIST * ns;
         ACTIONS * a1;
- int start;
- int chunk;
- int length;
 
         /* Only do rules with commands to execute. If this action has already
          * been executed, use saved status.
@@ -972,7 +1030,8 @@
         ns = make1list( L0, a0->action->sources, actions->flags );
         if ( actions->flags & RULE_TOGETHER )
             for ( a1 = a0->next; a1; a1 = a1->next )
- if ( a1->action->rule == rule && a1->action->running < running_flag )
+ if ( a1->action->rule == rule &&
+ a1->action->running < running_flag )
                 {
                     ns = make1list( ns, a1->action->sources, actions->flags );
                     a1->action->running = running_flag;
@@ -981,7 +1040,8 @@
         /* If doing only updated (or existing) sources, but none have been
          * updated (or exist), skip this action.
          */
- if ( list_empty( ns ) && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
+ if ( list_empty( ns ) &&
+ ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
         {
             list_free( nt );
             continue;
@@ -990,7 +1050,8 @@
         swap_settings( &settings_module, &settings_target, rule->module, t );
         if ( list_empty( shell ) )
         {
- shell = var_get( rule->module, constant_JAMSHELL ); /* shell is per-target */
+ /* shell is per-target */
+ shell = var_get( rule->module, constant_JAMSHELL );
         }
 
         /* If we had 'actions xxx bind vars' we bind the vars now. */
@@ -1000,66 +1061,112 @@
         /*
          * Build command, starting with all source args.
          *
- * If cmd_new returns 0, it is because the resulting command length is
- * > MAXLINE. In this case, we will slowly reduce the number of source
- * arguments presented until it does fit. This only applies to actions
- * that allow PIECEMEAL commands.
+ * For actions that allow PIECEMEAL commands, if the constructed command
+ * string is too long, we retry constructing it with a reduced number of
+ * source arguments presented.
          *
          * While reducing slowly takes a bit of compute time to get things just
- * right, it is worth it to get as close to MAXLINE as possible, because
- * launching the commands we are executing is likely to be much more
- * compute intensive.
+ * right, it is worth it to get as close to maximum allowed command
+ * string length as possible, because launching the commands we are
+ * executing is likely to be much more compute intensive.
          *
- * Note we loop through at least once, for sourceless actions.
+ * Note that we loop through at least once, for sourceless actions.
          */
+ {
+ int const length = list_length( ns );
+ int start = 0;
+ int chunk = length;
+ LIST * cmd_targets = L0;
+ LIST * cmd_shell = L0;
+ do
+ {
+ CMD * cmd;
+ int cmd_check_result;
+ int cmd_error_length;
+ int cmd_error_max_length;
+ int retry = 0;
+ int accept_command = 0;
+
+ /* Build cmd: cmd_new() takes ownership of its lists. */
+ if ( list_empty( cmd_targets ) ) cmd_targets = list_copy( nt );
+ if ( list_empty( cmd_shell ) ) cmd_shell = list_copy( shell );
+ cmd = cmd_new( rule, cmd_targets, list_sublist( ns, start,
+ chunk ), cmd_shell );
 
- start = 0;
- chunk = length = list_length( ns );
+ cmd_check_result = exec_check( cmd->buf, &cmd->shell,
+ &cmd_error_length, &cmd_error_max_length );
 
- do
- {
- /* Build cmd: cmd_new consumes its lists. */
- CMD * cmd = cmd_new( rule,
- list_copy( nt ),
- list_sublist( ns, start, chunk ),
- list_copy( shell ) );
+ if ( cmd_check_result == EXEC_CHECK_OK )
+ {
+ accept_command = 1;
+ }
+ else if ( cmd_check_result == EXEC_CHECK_NOOP )
+ {
+ accept_command = 1;
+ cmd->noop = 1;
+ }
+ else if ( ( actions->flags & RULE_PIECEMEAL ) && ( chunk > 1 ) )
+ {
+ /* Too long but splittable. Reduce chunk size slowly and
+ * retry.
+ */
+ assert( cmd_check_result == EXEC_CHECK_TOO_LONG ||
+ cmd_check_result == EXEC_CHECK_LINE_TOO_LONG );
+ chunk = chunk * 9 / 10;
+ retry = 1;
+ }
+ else
+ {
+ /* Too long and not splittable. */
+ char const * const error_message = cmd_check_result ==
+ EXEC_CHECK_TOO_LONG
+ ? "is too long"
+ : "contains a line that is too long";
+ assert( cmd_check_result == EXEC_CHECK_TOO_LONG ||
+ cmd_check_result == EXEC_CHECK_LINE_TOO_LONG );
+ printf( "%s action %s (%d, max %d):\n", object_str(
+ rule->name ), error_message, cmd_error_length,
+ cmd_error_max_length );
+
+ /* Tell the user what did not fit. */
+ fputs( cmd->buf->value, stdout );
+ exit( EXITBAD );
+ }
 
- if ( cmd )
- {
- /* It fit: chain it up. */
- if ( !cmds ) cmds = cmd;
- else cmds->tail->next = cmd;
- cmds->tail = cmd;
- start += chunk;
- }
- else if ( ( actions->flags & RULE_PIECEMEAL ) && ( chunk > 1 ) )
- {
- /* Reduce chunk size slowly. */
- chunk = chunk * 9 / 10;
- }
- else
- {
- /* Too long and not splittable. */
- printf( "%s actions too long (max %d):\n", object_str( rule->name ), MAXLINE
- );
+ assert( !retry || !accept_command );
 
- /* Tell the user what didn't fit. */
- cmd = cmd_new( rule, list_copy( nt ),
- list_sublist( ns, start, chunk ),
- list_new( object_copy( constant_percent ) ) );
- fputs( cmd->buf->value, stdout );
- exit( EXITBAD );
+ if ( accept_command )
+ {
+ /* Chain it up. */
+ *cmds_next = cmd;
+ cmds_next = &cmd->next;
+
+ /* Mark lists we need recreated for the next command since
+ * they got consumed by the cmd object.
+ */
+ cmd_targets = L0;
+ cmd_shell = L0;
+ }
+ else
+ {
+ /* We can reuse targets & shell lists for the next command
+ * if we do not let them die with this cmd object.
+ */
+ cmd_release_targets_and_shell( cmd );
+ cmd_free( cmd );
+ }
+
+ if ( !retry )
+ start += chunk;
             }
+ while ( start < length );
         }
- while ( start < length );
 
         /* These were always copied when used. */
         list_free( nt );
         list_free( ns );
 
- /* Free the variables whose values were bound by 'actions xxx bind
- * vars'.
- */
+ /* Free variables with values bound by 'actions xxx bind vars'. */
         popsettings( rule->module, boundvars );
         freesettings( boundvars );
     }
@@ -1070,7 +1177,7 @@
 
 
 /*
- * make1list() - turn a list of targets into a LIST, for $(<) and $(>).
+ * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
  */
 
 static LIST * make1list( LIST * l, TARGETS * targets, int flags )
@@ -1084,22 +1191,26 @@
 
         if ( ( flags & RULE_EXISTING ) && ( flags & RULE_NEWSRCS ) )
         {
- if ( ( t->binding != T_BIND_EXISTS ) && ( t->fate <= T_FATE_STABLE ) )
+ if ( ( t->binding != T_BIND_EXISTS ) &&
+ ( t->fate <= T_FATE_STABLE ) )
                 continue;
         }
- else
+ else if ( flags & RULE_EXISTING )
         {
- if ( ( flags & RULE_EXISTING ) && ( t->binding != T_BIND_EXISTS ) )
+ if ( t->binding != T_BIND_EXISTS )
                 continue;
-
- if ( ( flags & RULE_NEWSRCS ) && ( t->fate <= T_FATE_STABLE ) )
+ }
+ else if ( flags & RULE_NEWSRCS )
+ {
+ if ( t->fate <= T_FATE_STABLE )
                 continue;
         }
 
         /* Prohibit duplicates for RULE_TOGETHER. */
         if ( flags & RULE_TOGETHER )
         {
- LISTITER iter = list_begin( l ), end = list_end( l );
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
             for ( ; iter != end; iter = list_next( iter ) )
                 if ( object_equal( list_item( iter ), t->boundname ) )
                     break;
@@ -1116,23 +1227,25 @@
 
 
 /*
- * make1settings() - for vars that get bound values, build up replacement lists.
+ * make1settings() - for vars with bound values, build up replacement lists
  */
 
 static SETTINGS * make1settings( struct module_t * module, LIST * vars )
 {
     SETTINGS * settings = 0;
 
- LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+ LISTITER vars_iter = list_begin( vars );
+ LISTITER const vars_end = list_end( vars );
     for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
     {
- LIST * l = var_get( module, list_item( vars_iter ) );
+ LIST * const l = var_get( module, list_item( vars_iter ) );
         LIST * nl = L0;
- LISTITER iter = list_begin( l ), end = list_end( l );
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
 
         for ( ; iter != end; iter = list_next( iter ) )
         {
- TARGET * t = bindtarget( list_item( iter ) );
+ TARGET * const t = bindtarget( list_item( iter ) );
 
             /* Make sure the target is bound. */
             if ( t->binding == T_BIND_UNBOUND )
@@ -1164,7 +1277,7 @@
 
     pushsettings( root_module(), t->settings );
     object_free( t->boundname );
- t->boundname = search( t->name, &t->time, 0, ( t->flags & T_FLAG_ISFILE ) );
- t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
+ t->boundname = search( t->name, &t->time, 0, t->flags & T_FLAG_ISFILE );
+ t->binding = timestamp_empty( &t->time ) ? T_BIND_MISSING : T_BIND_EXISTS;
     popsettings( root_module(), t->settings );
 }

Modified: branches/release/tools/build/v2/engine/mem.h
==============================================================================
--- branches/release/tools/build/v2/engine/mem.h (original)
+++ branches/release/tools/build/v2/engine/mem.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,18 +1,18 @@
 /*
-Copyright Rene Rivera 2006.
-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)
-*/
+ * Copyright 2006. Rene Rivera
+ * 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)
+ */
 
 #ifndef BJAM_MEM_H
 #define BJAM_MEM_H
 
-
 #ifdef OPT_BOEHM_GC
 
     /* Use Boehm GC memory allocator. */
     #include <gc.h>
+
     #define bjam_malloc_x(s) memset(GC_malloc(s),0,s)
     #define bjam_malloc_atomic_x(s) memset(GC_malloc_atomic(s),0,s)
     #define bjam_calloc_x(n,s) memset(GC_malloc((n)*(s)),0,(n)*(s))
@@ -27,13 +27,14 @@
     #define bjam_free_raw_x(p) free(p)
 
     #ifndef BJAM_NEWSTR_NO_ALLOCATE
- #define BJAM_NEWSTR_NO_ALLOCATE
+ # define BJAM_NEWSTR_NO_ALLOCATE
     #endif
 
-#elif defined(OPT_DUMA)
+#elif defined( OPT_DUMA )
 
     /* Use Duma memory debugging library. */
     #include <stdlib.h>
+
     #define _DUMA_CONFIG_H_
     #define DUMA_NO_GLOBAL_MALLOC_FREE
     #define DUMA_EXPLICIT_INIT
@@ -50,18 +51,21 @@
     typedef unsigned int DUMA_ADDR;
     typedef unsigned int DUMA_SIZE;
     #include <duma.h>
+
     #define bjam_malloc_x(s) malloc(s)
     #define bjam_calloc_x(n,s) calloc(n,s)
     #define bjam_realloc_x(p,s) realloc(p,s)
     #define bjam_free_x(p) free(p)
 
     #ifndef BJAM_NEWSTR_NO_ALLOCATE
- #define BJAM_NEWSTR_NO_ALLOCATE
+ # define BJAM_NEWSTR_NO_ALLOCATE
     #endif
 
 #else
 
     /* Standard C memory allocation. */
+ #include <stdlib.h>
+
     #define bjam_malloc_x(s) malloc(s)
     #define bjam_calloc_x(n,s) calloc(n,s)
     #define bjam_realloc_x(p,s) realloc(p,s)
@@ -95,40 +99,35 @@
 #endif
 
 #ifdef OPT_DEBUG_PROFILE
-
     /* Profile tracing of memory allocations. */
+ #include "debug.h"
+
     #define BJAM_MALLOC(s) (profile_memory(s), bjam_malloc_x(s))
     #define BJAM_MALLOC_ATOMIC(s) (profile_memory(s), bjam_malloc_atomic_x(s))
     #define BJAM_CALLOC(n,s) (profile_memory(n*s), bjam_calloc_x(n,s))
     #define BJAM_CALLOC_ATOMIC(n,s) (profile_memory(n*s), bjam_calloc_atomic_x(n,s))
     #define BJAM_REALLOC(p,s) (profile_memory(s), bjam_realloc_x(p,s))
- #define BJAM_FREE(p) bjam_free_x(p)
- #define BJAM_MEM_INIT() bjam_mem_init_x()
- #define BJAM_MEM_CLOSE() bjam_mem_close_x()
 
     #define BJAM_MALLOC_RAW(s) (profile_memory(s), bjam_malloc_raw_x(s))
     #define BJAM_CALLOC_RAW(n,s) (profile_memory(n*s), bjam_calloc_raw_x(n,s))
     #define BJAM_REALLOC_RAW(p,s) (profile_memory(s), bjam_realloc_raw_x(p,s))
- #define BJAM_FREE_RAW(p) bjam_free_raw_x(p)
-
 #else
-
     /* No mem tracing. */
     #define BJAM_MALLOC(s) bjam_malloc_x(s)
     #define BJAM_MALLOC_ATOMIC(s) bjam_malloc_atomic_x(s)
     #define BJAM_CALLOC(n,s) bjam_calloc_x(n,s)
     #define BJAM_CALLOC_ATOMIC(n,s) bjam_calloc_atomic_x(n,s)
     #define BJAM_REALLOC(p,s) bjam_realloc_x(p,s)
- #define BJAM_FREE(p) bjam_free_x(p)
- #define BJAM_MEM_INIT() bjam_mem_init_x()
- #define BJAM_MEM_CLOSE() bjam_mem_close_x()
 
     #define BJAM_MALLOC_RAW(s) bjam_malloc_raw_x(s)
     #define BJAM_CALLOC_RAW(n,s) bjam_calloc_raw_x(n,s)
     #define BJAM_REALLOC_RAW(p,s) bjam_realloc_raw_x(p,s)
- #define BJAM_FREE_RAW(p) bjam_free_raw_x(p)
-
 #endif
 
+#define BJAM_MEM_INIT() bjam_mem_init_x()
+#define BJAM_MEM_CLOSE() bjam_mem_close_x()
+
+#define BJAM_FREE(p) bjam_free_x(p)
+#define BJAM_FREE_RAW(p) bjam_free_raw_x(p)
 
 #endif

Modified: branches/release/tools/build/v2/engine/modules.c
==============================================================================
--- branches/release/tools/build/v2/engine/modules.c (original)
+++ branches/release/tools/build/v2/engine/modules.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,33 +1,34 @@
 /*
- * Copyright 2001-2004 David Abrahams.
- * 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)
+ * Copyright 2001-2004 David Abrahams.
+ * 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)
  */
-#include "jam.h"
 
+#include "jam.h"
 #include "modules.h"
-#include "string.h"
+
 #include "hash.h"
-#include "object.h"
 #include "lists.h"
+#include "native.h"
+#include "object.h"
 #include "parse.h"
 #include "rules.h"
-#include "variable.h"
 #include "strings.h"
-#include "native.h"
+#include "variable.h"
+
 #include <assert.h>
+#include <string.h>
 
 static struct hash * module_hash = 0;
 static module_t root;
 
+
 module_t * bindmodule( OBJECT * name )
 {
-
     if ( !name )
- {
         return &root;
- }
- else
+
     {
         PROFILE_ENTER( BINDMODULE );
 
@@ -58,6 +59,7 @@
     }
 }
 
+
 /*
  * demand_rules() - Get the module's "rules" hash on demand.
  */
@@ -93,6 +95,7 @@
     object_free( *(OBJECT * *)xmodule_name );
 }
 
+
 static void free_fixed_variable( void * xvar, void * data );
 
 void delete_module( module_t * m )
@@ -258,7 +261,7 @@
         hashenumerate( class_hash, print_class_stats, (void *)0 );
         hash_free( class_hash );
     }
- hashenumerate( module_hash, delete_module_, (void *)0 );
+ hashenumerate( module_hash, delete_module_, (void *)0 );
     hashdone( module_hash );
     module_hash = 0;
     delete_module( &root );
@@ -275,22 +278,23 @@
     PROFILE_ENTER( IMPORT_MODULE );
 
     struct hash * h;
- LISTITER iter, end;
+ LISTITER iter;
+ LISTITER end;
 
     if ( !target_module->imported_modules )
- target_module->imported_modules = hashinit( sizeof( char * ), "imported" );
+ target_module->imported_modules = hashinit( sizeof( char * ), "imported"
+ );
     h = target_module->imported_modules;
 
- iter = list_begin( module_names ), end = list_end( module_names );
+ iter = list_begin( module_names );
+ end = list_end( module_names );
     for ( ; iter != end; iter = list_next( iter ) )
     {
         int found;
- OBJECT * s = list_item( iter );
- OBJECT * * ss = (OBJECT * *)hash_insert( h, s, &found );
- if( !found )
- {
+ OBJECT * const s = list_item( iter );
+ OBJECT * * const ss = (OBJECT * *)hash_insert( h, s, &found );
+ if ( !found )
             *ss = object_copy( s );
- }
     }
 
     PROFILE_EXIT( IMPORT_MODULE );
@@ -299,9 +303,8 @@
 
 static void add_module_name( void * r_, void * result_ )
 {
- OBJECT * * r = (OBJECT * *)r_;
- LIST * * result = (LIST * *)result_;
-
+ OBJECT * * const r = (OBJECT * *)r_;
+ LIST * * const result = (LIST * *)result_;
     *result = list_push_back( *result, object_copy( *r ) );
 }
 
@@ -315,8 +318,8 @@
 }
 
 
-FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
-FUNCTION * function_unbind_variables( FUNCTION * f );
+FUNCTION * function_bind_variables( FUNCTION *, module_t *, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * );
 
 struct fixed_variable
 {
@@ -330,19 +333,23 @@
     int counter;
 };
 
+
 static void free_fixed_variable( void * xvar, void * data )
 {
     object_free( ( (struct fixed_variable *)xvar )->key );
 }
 
+
 static void bind_variables_for_rule( void * xrule, void * xdata )
 {
     RULE * rule = (RULE *)xrule;
     struct bind_vars_t * data = (struct bind_vars_t *)xdata;
     if ( rule->procedure && rule->module == data->module )
- rule->procedure = function_bind_variables( rule->procedure, data->module, &data->counter );
+ rule->procedure = function_bind_variables( rule->procedure,
+ data->module, &data->counter );
 }
 
+
 void module_bind_variables( struct module_t * m )
 {
     if ( m != root_module() && m->rules )
@@ -355,6 +362,7 @@
     }
 }
 
+
 int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
 {
     struct fixed_variable * v;
@@ -375,6 +383,7 @@
     return v->n;
 }
 
+
 LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
 
 static void load_fixed_variable( void * xvar, void * data )
@@ -382,11 +391,10 @@
     struct fixed_variable * var = (struct fixed_variable *)xvar;
     struct module_t * m = (struct module_t *)data;
     if ( var->n >= m->num_fixed_variables )
- {
         m->fixed_variables[ var->n ] = var_get_and_clear_raw( m, var->key );
- }
 }
 
+
 void module_set_fixed_variables( struct module_t * m, int n_variables )
 {
     /* Reallocate */
@@ -394,43 +402,30 @@
     LIST * * fixed_variables = BJAM_MALLOC( n_variables * sizeof( LIST * ) );
     if ( m->fixed_variables )
     {
- memcpy( fixed_variables, m->fixed_variables, n_variables * sizeof( LIST * ) );
+ memcpy( fixed_variables, m->fixed_variables, m->num_fixed_variables * sizeof( LIST * ) );
         BJAM_FREE( m->fixed_variables );
     }
     m->fixed_variables = fixed_variables;
- if ( m->class_module )
- {
- variable_indices = m->class_module->variable_indices;
- }
- else
- {
- variable_indices = m->variable_indices;
- }
+ variable_indices = m->class_module
+ ? m->class_module->variable_indices
+ : m->variable_indices;
     if ( variable_indices )
         hashenumerate( variable_indices, &load_fixed_variable, m );
     m->num_fixed_variables = n_variables;
 }
 
+
 int module_get_fixed_var( struct module_t * m_, OBJECT * name )
 {
     struct fixed_variable * v;
     struct module_t * m = m_;
 
     if ( m->class_module )
- {
         m = m->class_module;
- }
 
     if ( !m->variable_indices )
         return -1;
 
     v = (struct fixed_variable *)hash_find( m->variable_indices, name );
- if ( v && v->n < m_->num_fixed_variables )
- {
- return v->n;
- }
- else
- {
- return -1;
- }
+ return v && v->n < m_->num_fixed_variables ? v->n : -1;
 }

Modified: branches/release/tools/build/v2/engine/modules.h
==============================================================================
--- branches/release/tools/build/v2/engine/modules.h (original)
+++ branches/release/tools/build/v2/engine/modules.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,10 +4,12 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 #ifndef MODULES_DWA10182001_H
-# define MODULES_DWA10182001_H
+#define MODULES_DWA10182001_H
 
 #include "lists.h"
+#include "object.h"
 
+typedef struct module_t module_t ;
 struct module_t
 {
     OBJECT * name;
@@ -17,37 +19,34 @@
     int num_fixed_variables;
     LIST * * fixed_variables;
     struct hash * imported_modules;
- struct module_t * class_module;
+ module_t * class_module;
     struct hash * native_rules;
     int user_module;
 };
 
-typedef struct module_t module_t ; /* MSVC debugger gets confused unless this is provided */
-
 module_t * bindmodule( OBJECT * name );
 module_t * root_module();
 void delete_module( module_t * );
 
 void import_module( LIST * module_names, module_t * target_module );
-LIST* imported_modules(module_t* module);
+LIST * imported_modules( module_t * );
 
 struct hash * demand_rules( module_t * );
 
-void module_bind_variables( struct module_t * m );
+void module_bind_variables( module_t * );
 
 /*
- * After calling module_add_fixed_var, module_set_fixed_variables
- * must be called before accessing any variables in the module.
+ * After calling module_add_fixed_var, module_set_fixed_variables must be called
+ * before accessing any variables in the module.
  */
-int module_add_fixed_var( struct module_t * m, OBJECT * name, int * n );
-void module_set_fixed_variables( struct module_t * m, int n );
+int module_add_fixed_var( module_t *, OBJECT * name, int * n );
+void module_set_fixed_variables( module_t *, int n );
 
 /*
  * Returns the index of the variable or -1 if none exists.
  */
-int module_get_fixed_var( struct module_t * m, OBJECT * name );
+int module_get_fixed_var( module_t *, OBJECT * name );
 
 void modules_done();
 
 #endif
-

Modified: branches/release/tools/build/v2/engine/modules/order.c
==============================================================================
--- branches/release/tools/build/v2/engine/modules/order.c (original)
+++ branches/release/tools/build/v2/engine/modules/order.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,147 +1,160 @@
-/* Copyright Vladimir Prus 2004. 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) */
+/* Copyright 2004. Vladimir Prus
+ * 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)
+ */
 
-#include "../native.h"
 #include "../lists.h"
-#include "../strings.h"
+#include "../mem.h"
+#include "../native.h"
 #include "../object.h"
+#include "../strings.h"
 #include "../variable.h"
 
 
-/* Use quite klugy approach: when we add order dependency from 'a' to 'b',
- just append 'b' to of value of variable 'a'.
-*/
-LIST *add_pair( FRAME *frame, int flags )
-{
- LIST* arg = lol_get( frame->args, 0 );
- LISTITER iter = list_begin( arg ), end = list_end( arg );
-
- var_set( frame->module, list_item( iter ), list_copy_range( arg, list_next( iter ), end ), VAR_APPEND );
-
+/* Use quite klugy approach: when we add order dependency from 'a' to 'b', just
+ * append 'b' to of value of variable 'a'.
+ */
+LIST * add_pair( FRAME * frame, int flags )
+{
+ LIST * arg = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg );
+ LISTITER const end = list_end( arg );
+ var_set( frame->module, list_item( iter ), list_copy_range( arg, list_next(
+ iter ), end ), VAR_APPEND );
     return L0;
 }
 
-/** Given a list and a value, returns position of that value in
- the list, or -1 if not found.
-*/
-int list_index(LIST* list, OBJECT* value)
+
+/* Given a list and a value, returns position of that value in the list, or -1
+ * if not found.
+ */
+int list_index( LIST * list, OBJECT * value )
 {
     int result = 0;
- LISTITER iter = list_begin(list), end = list_end(list);
- for(; iter != end; iter = list_next(iter), ++result) {
- if (object_equal(list_item(iter), value))
+ LISTITER iter = list_begin( list );
+ LISTITER const end = list_end( list );
+ for ( ; iter != end; iter = list_next( iter ), ++result )
+ if ( object_equal( list_item( iter ), value ) )
             return result;
- }
     return -1;
 }
 
 enum colors { white, gray, black };
 
-/* Main routite of topological sort. Calls itself recursively on all
- adjacent vertices which were not yet visited. After that, 'current_vertex'
- is added to '*result_ptr'.
-*/
-void do_ts(int** graph, int current_vertex, int* colors, int** result_ptr)
+
+/* Main routine for topological sort. Calls itself recursively on all adjacent
+ * vertices which were not yet visited. After that, 'current_vertex' is added to
+ * '*result_ptr'.
+ */
+void do_ts( int * * graph, int current_vertex, int * colors, int * * result_ptr
+ )
 {
     int i;
 
- colors[current_vertex] = gray;
- for(i = 0; graph[current_vertex][i] != -1; ++i) {
- int adjacent_vertex = graph[current_vertex][i];
-
- if (colors[adjacent_vertex] == white)
- do_ts(graph, adjacent_vertex, colors, result_ptr);
- /* The vertex is either black, in which case we don't have to do
- anything, a gray, in which case we have a loop. If we have a loop,
- it's not clear what useful diagnostic we can emit, so we emit
- nothing. */
- }
- colors[current_vertex] = black;
- **result_ptr = current_vertex;
- (*result_ptr)++;
+ colors[ current_vertex ] = gray;
+ for ( i = 0; graph[ current_vertex ][ i ] != -1; ++i )
+ {
+ int adjacent_vertex = graph[ current_vertex ][ i ];
+ if ( colors[ adjacent_vertex ] == white )
+ do_ts( graph, adjacent_vertex, colors, result_ptr );
+ /* The vertex is either black, in which case we do not have to do
+ * anything, or gray, in which case we have a loop. If we have a loop,
+ * it is not clear what useful diagnostic we can emit, so we emit
+ * nothing.
+ */
+ }
+ colors[ current_vertex ] = black;
+ **result_ptr = current_vertex;
+ ( *result_ptr )++;
 }
 
-void topological_sort(int** graph, int num_vertices, int* result)
+
+void topological_sort( int * * graph, int num_vertices, int * result )
 {
     int i;
- int* colors = (int*)BJAM_CALLOC(num_vertices, sizeof(int));
- for (i = 0; i < num_vertices; ++i)
- colors[i] = white;
+ int * colors = ( int * )BJAM_CALLOC( num_vertices, sizeof( int ) );
+ for ( i = 0; i < num_vertices; ++i )
+ colors[ i ] = white;
 
- for(i = 0; i < num_vertices; ++i)
- if (colors[i] == white)
- do_ts(graph, i, colors, &result);
+ for ( i = 0; i < num_vertices; ++i )
+ if ( colors[ i ] == white )
+ do_ts( graph, i, colors, &result );
 
- BJAM_FREE(colors);
+ BJAM_FREE( colors );
 }
 
-LIST *order( FRAME *frame, int flags )
+
+LIST * order( FRAME * frame, int flags )
 {
- LIST* arg = lol_get( frame->args, 0 );
- LIST* result = L0;
+ LIST * arg = lol_get( frame->args, 0 );
+ LIST * result = L0;
     int src;
- LISTITER iter = list_begin(arg), end = list_end(arg);
+ LISTITER iter = list_begin( arg );
+ LISTITER const end = list_end( arg );
+
+ /* We need to create a graph of order dependencies between the passed
+ * objects. We assume there are no duplicates passed to 'add_pair'.
+ */
+ int length = list_length( arg );
+ int * * graph = ( int * * )BJAM_CALLOC( length, sizeof( int * ) );
+ int * order = ( int * )BJAM_MALLOC( ( length + 1 ) * sizeof( int ) );
 
- /* We need to create a graph of order dependencies between
- the passed objects. We assume that there are no duplicates
- passed to 'add_pair'.
- */
- int length = list_length(arg);
- int** graph = (int**)BJAM_CALLOC(length, sizeof(int*));
- int* order = (int*)BJAM_MALLOC((length+1)*sizeof(int));
-
- for(src = 0; iter != end; iter = list_next(iter), ++src) {
- /* For all object this one depend upon, add elements
- to 'graph' */
- LIST* dependencies = var_get(frame->module, list_item(iter));
+ for ( src = 0; iter != end; iter = list_next( iter ), ++src )
+ {
+ /* For all objects this one depends upon, add elements to 'graph'. */
+ LIST * dependencies = var_get( frame->module, list_item( iter ) );
         int index = 0;
- LISTITER dep_iter = list_begin(dependencies), dep_end = list_end(dependencies);
+ LISTITER dep_iter = list_begin( dependencies );
+ LISTITER const dep_end = list_end( dependencies );
 
- graph[src] = (int*)BJAM_CALLOC(list_length(dependencies)+1, sizeof(int));
- for(; dep_iter != dep_end; dep_iter = list_next(dep_iter)) {
- int dst = list_index(arg, list_item(dep_iter));
- if (dst != -1)
- graph[src][index++] = dst;
+ graph[ src ] = ( int * )BJAM_CALLOC( list_length( dependencies ) + 1,
+ sizeof( int ) );
+ for ( ; dep_iter != dep_end; dep_iter = list_next( dep_iter ) )
+ {
+ int const dst = list_index( arg, list_item( dep_iter ) );
+ if ( dst != -1 )
+ graph[ src ][ index++ ] = dst;
         }
- graph[src][index] = -1;
+ graph[ src ][ index ] = -1;
     }
 
- topological_sort(graph, length, order);
+ topological_sort( graph, length, order );
 
     {
- int index = length-1;
- for(; index >= 0; --index) {
+ int index = length - 1;
+ for ( ; index >= 0; --index )
+ {
             int i;
- iter = list_begin(arg), end = list_end(arg);
- for (i = 0; i < order[index]; ++i, iter = list_next(iter));
- result = list_push_back(result, object_copy(list_item(iter)));
+ LISTITER iter = list_begin( arg );
+ LISTITER const end = list_end( arg );
+ for ( i = 0; i < order[ index ]; ++i, iter = list_next( iter ) );
+ result = list_push_back( result, object_copy( list_item( iter ) ) );
         }
     }
 
     /* Clean up */
     {
         int i;
- for(i = 0; i < length; ++i)
- BJAM_FREE(graph[i]);
- BJAM_FREE(graph);
- BJAM_FREE(order);
+ for ( i = 0; i < length; ++i )
+ BJAM_FREE( graph[ i ] );
+ BJAM_FREE( graph );
+ BJAM_FREE( order );
     }
 
     return result;
 }
 
+
 void init_order()
 {
     {
- const char* args[] = { "first", "second", 0 };
- declare_native_rule("class_at_order", "add-pair", args, add_pair, 1);
+ char const * args[] = { "first", "second", 0 };
+ declare_native_rule( "class_at_order", "add-pair", args, add_pair, 1 );
     }
 
     {
- const char* args[] = { "objects", "*", 0 };
- declare_native_rule("class_at_order", "order", args, order, 1);
+ char const * args[] = { "objects", "*", 0 };
+ declare_native_rule( "class_at_order", "order", args, order, 1 );
     }
-
-
 }

Modified: branches/release/tools/build/v2/engine/modules/path.c
==============================================================================
--- branches/release/tools/build/v2/engine/modules/path.c (original)
+++ branches/release/tools/build/v2/engine/modules/path.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,32 +1,25 @@
-/* Copyright Vladimir Prus 2003. 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) */
+/* Copyright Vladimir Prus 2003.
+ * 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)
+ */
 
+#include "../constants.h"
+#include "../frames.h"
+#include "../lists.h"
 #include "../native.h"
 #include "../timestamp.h"
-#include "../object.h"
 
-LIST *path_exists( FRAME *frame, int flags )
-{
- LIST* l = lol_get( frame->args, 0 );
 
- time_t time;
- timestamp(list_front(l), &time);
- if (time != 0)
- {
- return list_new(object_new("true"));
- }
- else
- {
- return L0;
- }
+LIST * path_exists( FRAME * frame, int flags )
+{
+ return file_query( list_front( lol_get( frame->args, 0 ) ) ) ?
+ list_new( object_copy( constant_true ) ) : L0;
 }
 
+
 void init_path()
 {
- {
- const char* args[] = { "location", 0 };
- declare_native_rule("path", "exists", args, path_exists, 1);
- }
-
+ char const * args[] = { "location", 0 };
+ declare_native_rule( "path", "exists", args, path_exists, 1 );
 }

Modified: branches/release/tools/build/v2/engine/modules/property-set.c
==============================================================================
--- branches/release/tools/build/v2/engine/modules/property-set.c (original)
+++ branches/release/tools/build/v2/engine/modules/property-set.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,117 +1,330 @@
-/* Copyright Vladimir Prus 2003. 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) */
+/*
+ * Copyright 2013 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)
+ */
 
-#include "../native.h"
-#include "../timestamp.h"
 #include "../object.h"
-#include "../strings.h"
 #include "../lists.h"
+#include "../modules.h"
+#include "../rules.h"
 #include "../variable.h"
+#include "../native.h"
 #include "../compile.h"
+#include "../mem.h"
+#include "../constants.h"
+#include "string.h"
 
-LIST* get_grist(char* f)
+struct ps_map_entry
 {
- char* end = strchr(f, '>');
- string s[1];
- LIST* result;
-
- string_new(s);
+ struct ps_map_entry * next;
+ LIST * key;
+ OBJECT * value;
+};
 
- string_append_range(s, f, end+1);
- result = list_new(object_new(s->value));
+struct ps_map
+{
+ struct ps_map_entry * * table;
+ size_t table_size;
+ size_t num_elems;
+};
 
- string_free(s);
- return result;
+static unsigned list_hash(LIST * key)
+{
+ unsigned int hash = 0;
+ LISTITER iter = list_begin( key ), end = list_end( key );
+ for ( ; iter != end; ++iter )
+ {
+ hash = hash * 2147059363 + object_hash( list_item( iter ) );
+ }
+ return hash;
 }
 
-/*
-rule create ( raw-properties * )
+static int list_equal( LIST * lhs, LIST * rhs )
 {
- raw-properties = [ sequence.unique
- [ sequence.insertion-sort $(raw-properties) ] ] ;
+ LISTITER lhs_iter, lhs_end, rhs_iter;
+ if ( list_length( lhs ) != list_length( rhs ) )
+ {
+ return 0;
+ }
+ lhs_iter = list_begin( lhs );
+ lhs_end = list_end( lhs );
+ rhs_iter = list_begin( rhs );
+ for ( ; lhs_iter != lhs_end; ++lhs_iter, ++rhs_iter )
+ {
+ if ( ! object_equal( list_item( lhs_iter ), list_item( rhs_iter ) ) )
+ {
+ return 0;
+ }
+ }
+ return 1;
+}
 
- local key = $(raw-properties:J=-:E=) ;
+static void ps_map_init( struct ps_map * map )
+{
+ size_t i;
+ map->table_size = 2;
+ map->num_elems = 0;
+ map->table = BJAM_MALLOC( map->table_size * sizeof( struct ps_map_entry * ) );
+ for ( i = 0; i < map->table_size; ++i )
+ {
+ map->table[ i ] = NULL;
+ }
+}
 
- if ! $(.ps.$(key))
+static void ps_map_destroy( struct ps_map * map )
+{
+ size_t i;
+ for ( i = 0; i < map->table_size; ++i )
     {
- .ps.$(key) = [ new property-set $(raw-properties) ] ;
+ struct ps_map_entry * pos;
+ for ( pos = map->table[ i ]; pos; )
+ {
+ struct ps_map_entry * tmp = pos->next;
+ BJAM_FREE( pos );
+ pos = tmp;
+ }
     }
- return $(.ps.$(key)) ;
+ BJAM_FREE( map->table );
 }
-*/
 
-LIST *property_set_create( FRAME *frame, int flags )
+static void ps_map_rehash( struct ps_map * map )
 {
- LIST* properties = lol_get( frame->args, 0 );
- LIST* sorted = L0;
-#if 0
- LIST* order_sensitive = 0;
-#endif
- LIST* unique;
- LIST* val;
- string var[1];
- OBJECT* name;
- LISTITER iter, end;
+ struct ps_map old = *map;
+ size_t i;
+ map->table = BJAM_MALLOC( map->table_size * 2 * sizeof( struct ps_map_entry * ) );
+ map->table_size *= 2;
+ for ( i = 0; i < map->table_size; ++i )
+ {
+ map->table[ i ] = NULL;
+ }
+ for ( i = 0; i < old.table_size; ++i )
+ {
+ struct ps_map_entry * pos;
+ for ( pos = old.table[ i ]; pos; )
+ {
+ struct ps_map_entry * tmp = pos->next;
+
+ unsigned hash_val = list_hash( pos->key );
+ unsigned bucket = hash_val % map->table_size;
+ pos->next = map->table[ bucket ];
+ map->table[ bucket ] = pos;
 
-#if 0
- /* Sort all properties which are not order sensitive */
- for(tmp = properties; tmp; tmp = tmp->next) {
- LIST* g = get_grist(tmp->string);
- LIST* att = call_rule("feature.attributes", frame, g, 0);
- if (list_in(att, "order-sensitive")) {
- order_sensitive = list_new( order_sensitive, copystr(tmp->string));
- } else {
- sorted = list_new( sorted, copystr(tmp->string));
+ pos = tmp;
         }
- list_free(att);
     }
+ BJAM_FREE( old.table );
+}
 
- sorted = list_sort(sorted);
- sorted = list_append(sorted, order_sensitive);
- unique = list_unique(sorted);
-#endif
- sorted = list_sort(properties);
- unique = list_unique(sorted);
+static struct ps_map_entry * ps_map_insert(struct ps_map * map, LIST * key)
+{
+ unsigned hash_val = list_hash( key );
+ unsigned bucket = hash_val % map->table_size;
+ struct ps_map_entry * pos;
+ for ( pos = map->table[bucket]; pos ; pos = pos->next )
+ {
+ if ( list_equal( pos->key, key ) )
+ return pos;
+ }
 
- string_new(var);
- string_append(var, ".ps.");
+ if ( map->num_elems >= map->table_size )
+ {
+ ps_map_rehash( map );
+ bucket = hash_val % map->table_size;
+ }
+ pos = BJAM_MALLOC( sizeof( struct ps_map_entry ) );
+ pos->next = map->table[bucket];
+ pos->key = key;
+ pos->value = 0;
+ map->table[bucket] = pos;
+ ++map->num_elems;
+ return pos;
+}
 
- iter = list_begin( unique ), end = list_end( unique );
- for( ; iter != end; iter = list_next( iter ) ) {
- string_append(var, object_str( list_item( iter ) ));
- string_push_back(var, '-');
+static struct ps_map all_property_sets;
+
+LIST * property_set_create( FRAME * frame, int flags )
+{
+ LIST * properties = lol_get( frame->args, 0 );
+ LIST * sorted = list_sort( properties );
+ LIST * unique = list_unique( sorted );
+ struct ps_map_entry * pos = ps_map_insert( &all_property_sets, unique );
+ list_free( sorted );
+ if ( pos->value )
+ {
+ list_free( unique );
+ return list_new( object_copy( pos->value ) );
     }
- name = object_new(var->value);
- val = var_get(frame->module, name);
- if (list_empty(val))
+ else
     {
- OBJECT* rulename = object_new("new");
- val = call_rule(rulename, frame,
- list_append(list_new(object_new("property-set")), unique), 0);
- object_free(rulename);
+ OBJECT * rulename = object_new( "new" );
+ OBJECT * varname = object_new( "self.raw" );
+ LIST * val = call_rule( rulename, frame,
+ list_new( object_new( "property-set" ) ), 0 );
+ LISTITER iter, end;
+ object_free( rulename );
+ pos->value = list_front( val );
+ var_set( bindmodule( pos->value ), varname, unique, VAR_SET );
+ object_free( varname );
+
+ for ( iter = list_begin( unique ), end = list_end( unique ); iter != end; ++iter )
+ {
+ const char * str = object_str( list_item( iter ) );
+ if ( str[ 0 ] != '<' || ! strchr( str, '>' ) )
+ {
+ string message[ 1 ];
+ string_new( message );
+ string_append( message, "Invalid property: '" );
+ string_append( message, str );
+ string_append( message, "'" );
+ rulename = object_new( "errors.error" );
+ call_rule( rulename, frame,
+ list_new( object_new( message->value ) ), 0 );
+ /* unreachable */
+ string_free( message );
+ object_free( rulename );
+ }
+ }
 
- var_set(frame->module, name, list_copy(val), VAR_SET);
+ return val;
     }
- else
+}
+
+/* binary search for the property value */
+LIST * property_set_get( FRAME * frame, int flags )
+{
+ OBJECT * varname = object_new( "self.raw" );
+ LIST * props = var_get( frame->module, varname );
+ const char * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ size_t name_len = strlen( name );
+ LISTITER begin, end;
+ LIST * result = L0;
+ object_free( varname );
+
+ /* Assumes random access */
+ begin = list_begin( props ), end = list_end( props );
+
+ while ( 1 )
     {
- list_free(unique);
- val = list_copy(val);
+ ptrdiff_t diff = (end - begin);
+ LISTITER mid = begin + diff / 2;
+ int res;
+ if ( diff == 0 )
+ {
+ return L0;
+ }
+ res = strncmp( object_str( list_item( mid ) ), name, name_len );
+ if ( res < 0 )
+ {
+ begin = mid + 1;
+ }
+ else if ( res > 0 )
+ {
+ end = mid;
+ }
+ else /* We've found the property */
+ {
+ /* Find the beginning of the group */
+ LISTITER tmp = mid;
+ while ( tmp > begin )
+ {
+ --tmp;
+ res = strncmp( object_str( list_item( tmp ) ), name, name_len );
+ if ( res != 0 )
+ {
+ ++tmp;
+ break;
+ }
+ }
+ begin = tmp;
+ /* Find the end of the group */
+ tmp = mid + 1;
+ while ( tmp < end )
+ {
+ res = strncmp( object_str( list_item( tmp ) ), name, name_len );
+ if ( res != 0 ) break;
+ ++tmp;
+ }
+ end = tmp;
+ break;
+ }
     }
- object_free(name);
 
- string_free(var);
- /* The 'unique' variable is freed in 'call_rule'. */
- list_free(sorted);
+ for ( ; begin != end; ++begin )
+ {
+ result = list_push_back( result,
+ object_new( object_str( list_item( begin ) ) + name_len ) );
+ }
+
+ return result;
+}
 
- return val;
+/* binary search for the property value */
+LIST * property_set_contains_features( FRAME * frame, int flags )
+{
+ OBJECT * varname = object_new( "self.raw" );
+ LIST * props = var_get( frame->module, varname );
+ LIST * features = lol_get( frame->args, 0 );
+ LIST * result = L0;
+ LISTITER features_iter = list_begin( features );
+ LISTITER features_end = list_end( features ) ;
+ object_free( varname );
 
+ for ( ; features_iter != features_end; ++features_iter )
+ {
+ const char * name = object_str( list_item( features_iter ) );
+ size_t name_len = strlen( name );
+ LISTITER begin, end;
+ /* Assumes random access */
+ begin = list_begin( props ), end = list_end( props );
+
+ while ( 1 )
+ {
+ ptrdiff_t diff = (end - begin);
+ LISTITER mid = begin + diff / 2;
+ int res;
+ if ( diff == 0 )
+ {
+ /* The feature is missing */
+ return L0;
+ }
+ res = strncmp( object_str( list_item( mid ) ), name, name_len );
+ if ( res < 0 )
+ {
+ begin = mid + 1;
+ }
+ else if ( res > 0 )
+ {
+ end = mid;
+ }
+ else /* We've found the property */
+ {
+ break;
+ }
+ }
+ }
+ return list_new( object_copy( constant_true ) );
 }
 
 void init_property_set()
 {
     {
- const char* args[] = { "raw-properties", "*", 0 };
- declare_native_rule("property-set", "create", args, property_set_create, 1);
+ char const * args[] = { "raw-properties", "*", 0 };
+ declare_native_rule( "property-set", "create", args, property_set_create, 1 );
     }
+ {
+ char const * args[] = { "feature", 0 };
+ declare_native_rule( "class_at_property-set", "get", args, property_set_get, 1 );
+ }
+ {
+ char const * args[] = { "features", "*", 0 };
+ declare_native_rule( "class_at_property-set", "contains-features", args, property_set_contains_features, 1 );
+ }
+ ps_map_init( &all_property_sets );
+}
+
+void property_set_done()
+{
+ ps_map_destroy( &all_property_sets );
 }

Modified: branches/release/tools/build/v2/engine/modules/regex.c
==============================================================================
--- branches/release/tools/build/v2/engine/modules/regex.c (original)
+++ branches/release/tools/build/v2/engine/modules/regex.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,13 +1,123 @@
-/* Copyright Vladimir Prus 2003. 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) */
+/*
+ * Copyright 2003. Vladimir Prus
+ * 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)
+ */
 
+#include "../mem.h"
 #include "../native.h"
-#include "../timestamp.h"
-#include "../object.h"
 #include "../strings.h"
-#include "../regexp.h"
-#include "../compile.h"
+#include "../subst.h"
+
+/*
+rule split ( string separator )
+{
+ local result ;
+ local s = $(string) ;
+
+ local match = 1 ;
+ while $(match)
+ {
+ match = [ MATCH ^(.*)($(separator))(.*) : $(s) ] ;
+ if $(match)
+ {
+ match += "" ; # in case 3rd item was empty - works around MATCH bug
+ result = $(match[3]) $(result) ;
+ s = $(match[1]) ;
+ }
+ }
+ return $(s) $(result) ;
+}
+*/
+
+LIST * regex_split( FRAME * frame, int flags )
+{
+ LIST * args = lol_get( frame->args, 0 );
+ OBJECT * s;
+ OBJECT * separator;
+ regexp * re;
+ const char * pos;
+ LIST * result = L0;
+ LISTITER iter = list_begin( args );
+ s = list_item( iter );
+ separator = list_item( list_next( iter ) );
+
+ re = regex_compile( separator );
+
+ pos = object_str( s );
+ while ( regexec( re, pos ) )
+ {
+ result = list_push_back( result, object_new_range( pos, re->startp[ 0 ] - pos ) );
+ pos = re->endp[ 0 ];
+ }
+
+ result = list_push_back( result, object_new( pos ) );
+
+ return result;
+}
+
+/*
+rule replace (
+ string # The string to modify.
+ match # The characters to replace.
+ replacement # The string to replace with.
+ )
+{
+ local result = "" ;
+ local parts = 1 ;
+ while $(parts)
+ {
+ parts = [ MATCH ^(.*)($(match))(.*) : $(string) ] ;
+ if $(parts)
+ {
+ parts += "" ;
+ result = "$(replacement)$(parts[3])$(result)" ;
+ string = $(parts[1]) ;
+ }
+ }
+ string ?= "" ;
+ result = "$(string)$(result)" ;
+ return $(result) ;
+}
+*/
+
+LIST * regex_replace( FRAME * frame, int flags )
+{
+ LIST * args = lol_get( frame->args, 0 );
+ OBJECT * s;
+ OBJECT * match;
+ OBJECT * replacement;
+ regexp * re;
+ const char * pos;
+ string buf[ 1 ];
+ LIST * result;
+ LISTITER iter = list_begin( args );
+ s = list_item( iter );
+ iter = list_next( iter );
+ match = list_item( iter );
+ iter = list_next( iter );
+ replacement = list_item(iter );
+
+ re = regex_compile( match );
+
+ string_new( buf );
+
+ pos = object_str( s );
+ while ( regexec( re, pos ) )
+ {
+ string_append_range( buf, pos, re->startp[ 0 ] );
+ string_append( buf, object_str( replacement ) );
+ pos = re->endp[ 0 ];
+ }
+ string_append( buf, pos );
+
+ result = list_new( object_new( buf->value ) );
+
+ string_free( buf );
+
+ return result;
+}
 
 /*
 rule transform ( list * : pattern : indices * )
@@ -20,62 +130,66 @@
         if $(m)
         {
             result += $(m[$(indices)]) ;
- }
+ }
     }
     return $(result) ;
 }
 */
-LIST *regex_transform( FRAME *frame, int flags )
+
+LIST * regex_transform( FRAME * frame, int flags )
 {
- LIST* l = lol_get( frame->args, 0 );
- LIST* pattern = lol_get( frame->args, 1 );
- LIST* indices_list = lol_get(frame->args, 2);
- int* indices = 0;
+ LIST * const l = lol_get( frame->args, 0 );
+ LIST * const pattern = lol_get( frame->args, 1 );
+ LIST * const indices_list = lol_get( frame->args, 2 );
+ int * indices = 0;
     int size;
- int* p;
- LIST* result = L0;
+ LIST * result = L0;
 
- string buf[1];
- string_new(buf);
-
- if (!list_empty(indices_list))
+ if ( !list_empty( indices_list ) )
     {
- LISTITER iter = list_begin(indices_list), end = list_end(indices_list);
- size = list_length(indices_list);
- indices = (int*)BJAM_MALLOC(size*sizeof(int));
- for(p = indices; iter != end; iter = list_next(iter))
- {
- *p++ = atoi(object_str(list_item(iter)));
- }
+ int * p;
+ LISTITER iter = list_begin( indices_list );
+ LISTITER const end = list_end( indices_list );
+ size = list_length( indices_list );
+ indices = (int *)BJAM_MALLOC( size * sizeof( int ) );
+ for ( p = indices; iter != end; iter = list_next( iter ) )
+ *p++ = atoi( object_str( list_item( iter ) ) );
     }
- else
+ else
     {
         size = 1;
- indices = (int*)BJAM_MALLOC(sizeof(int));
+ indices = (int *)BJAM_MALLOC( sizeof( int ) );
         *indices = 1;
     }
 
     {
         /* Result is cached and intentionally never freed */
- regexp *re = regex_compile( list_front( pattern ) );
+ regexp * const re = regex_compile( list_front( pattern ) );
+
+ LISTITER iter = list_begin( l );
+ LISTITER const end = list_end( l );
 
- LISTITER iter = list_begin( l ), end = list_end( l );
- for( ; iter != end; iter = list_next( iter ) )
+ string buf[ 1 ];
+ string_new( buf );
+
+ for ( ; iter != end; iter = list_next( iter ) )
         {
- if( regexec( re, object_str( list_item( iter ) ) ) )
+ if ( regexec( re, object_str( list_item( iter ) ) ) )
             {
                 int i = 0;
- for(; i < size; ++i)
+ for ( ; i < size; ++i )
                 {
- int index = indices[i];
- /* Skip empty submatches. Not sure it's right in all cases,
- but surely is right for the case for which this routine
- is optimized -- header scanning.
- */
- if (re->startp[index] != re->endp[index])
+ int const index = indices[ i ];
+ /* Skip empty submatches. Not sure it is right in all cases,
+ * but surely is right for the case for which this routine
+ * is optimized -- header scanning.
+ */
+ if ( re->startp[ index ] != re->endp[ index ] )
                     {
- string_append_range( buf, re->startp[index], re->endp[index] );
- result = list_push_back( result, object_new( buf->value ) );
+ string_append_range( buf, re->startp[ index ],
+ re->endp[ index ] );
+ result = list_push_back( result, object_new( buf->value
+ ) );
                         string_truncate( buf, 0 );
                     }
                 }
@@ -84,15 +198,23 @@
         string_free( buf );
     }
 
- BJAM_FREE(indices);
-
+ BJAM_FREE( indices );
     return result;
 }
 
+
 void init_regex()
 {
     {
- const char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
- declare_native_rule("regex", "transform", args, regex_transform, 2);
+ char const * args[] = { "string", "separator", 0 };
+ declare_native_rule( "regex", "split", args, regex_split, 1 );
+ }
+ {
+ char const * args[] = { "string", "match", "replacement", 0 };
+ declare_native_rule( "regex", "replace", args, regex_replace, 1 );
+ }
+ {
+ char const * args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
+ declare_native_rule( "regex", "transform", args, regex_transform, 2 );
     }
 }

Modified: branches/release/tools/build/v2/engine/modules/sequence.c
==============================================================================
--- branches/release/tools/build/v2/engine/modules/sequence.c (original)
+++ branches/release/tools/build/v2/engine/modules/sequence.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,47 +1,97 @@
-/* Copyright Vladimir Prus 2003. 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) */
+/*
+ * Copyright Vladimir Prus 2003.
+ * 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)
+ */
 
 #include "../native.h"
 #include "../object.h"
+#include "../lists.h"
+#include "../compile.h"
 
-# ifndef max
-# define max( a,b ) ((a)>(b)?(a):(b))
-# endif
+#include <stdlib.h>
 
 
-LIST *sequence_select_highest_ranked( FRAME *frame, int flags )
+#ifndef max
+# define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+
+LIST * sequence_select_highest_ranked( FRAME * frame, int flags )
 {
    /* Returns all of 'elements' for which corresponding element in parallel */
    /* list 'rank' is equal to the maximum value in 'rank'. */
 
- LIST* elements = lol_get( frame->args, 0 );
- LIST* rank = lol_get( frame->args, 1 );
- LISTITER iter, end, elements_iter, elements_end;
-
- LIST* result = L0;
- LIST* tmp;
+ LIST * const elements = lol_get( frame->args, 0 );
+ LIST * const rank = lol_get( frame->args, 1 );
+
+ LIST * result = L0;
     int highest_rank = -1;
 
- iter = list_begin(rank), end = list_end(rank);
- for (; iter != end; iter = list_next(iter))
- highest_rank = max(highest_rank, atoi(object_str(list_item(iter))));
-
- iter = list_begin(rank), end = list_end(rank);
- elements_iter = list_begin(elements), elements_end = list_end(elements);
- for (; iter != end; iter = list_next(iter), elements_iter = list_next(elements_iter))
- if (atoi(object_str(list_item(iter))) == highest_rank)
- result = list_push_back(result, object_copy(list_item(elements_iter)));
+ {
+ LISTITER iter = list_begin( rank );
+ LISTITER const end = list_end( rank );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ int const current = atoi( object_str( list_item( iter ) ) );
+ highest_rank = max( highest_rank, current );
+ }
+ }
+
+ {
+ LISTITER iter = list_begin( rank );
+ LISTITER const end = list_end( rank );
+ LISTITER elements_iter = list_begin( elements );
+ LISTITER const elements_end = list_end( elements );
+ for ( ; iter != end; iter = list_next( iter ), elements_iter =
+ list_next( elements_iter ) )
+ if ( atoi( object_str( list_item( iter ) ) ) == highest_rank )
+ result = list_push_back( result, object_copy( list_item(
+ elements_iter ) ) );
+ }
 
     return result;
 }
 
-void init_sequence()
+LIST * sequence_transform( FRAME * frame, int flags )
 {
+ LIST * function = lol_get( frame->args, 0 );
+ LIST * sequence = lol_get( frame->args, 1 );
+ LIST * result = L0;
+ OBJECT * function_name = list_front( function );
+ LISTITER args_begin = list_next( list_begin( function ) ), args_end = list_end( function );
+ LISTITER iter = list_begin( sequence ), end = list_end( sequence );
+ RULE * rule = bindrule( function_name, frame->prev->module );
+
+ for ( ; iter != end; iter = list_next( iter ) )
     {
- const char* args[] = { "elements", "*", ":", "rank", "*", 0 };
- declare_native_rule("sequence", "select-highest-ranked", args,
- sequence_select_highest_ranked, 1);
+ FRAME inner[ 1 ];
+
+ frame_init( inner );
+ inner->prev = frame;
+ inner->prev_user = frame->prev_user;
+ inner->module = frame->prev->module;
+
+ lol_add( inner->args, list_push_back( list_copy_range( function, args_begin, args_end ), object_copy( list_item( iter ) ) ) );
+ result = list_append( result, evaluate_rule( rule, function_name, inner ) );
+
+ frame_free( inner );
     }
 
+ return result;
+}
+
+void init_sequence()
+{
+ {
+ char const * args[] = { "elements", "*", ":", "rank", "*", 0 };
+ declare_native_rule( "sequence", "select-highest-ranked", args,
+ sequence_select_highest_ranked, 1 );
+ }
+ {
+ char const * args[] = { "function", "+", ":", "sequence", "*", 0 };
+ declare_native_rule( "sequence", "transform", args,
+ sequence_transform, 1 );
+ }
 }

Modified: branches/release/tools/build/v2/engine/native.c
==============================================================================
--- branches/release/tools/build/v2/engine/native.c (original)
+++ branches/release/tools/build/v2/engine/native.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,36 +1,31 @@
-/* Copyright Vladimir Prus 2003. 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) */
+/* Copyright 2003. Vladimir Prus
+ * 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)
+ */
 
 #include "native.h"
+
 #include "hash.h"
-#include "object.h"
-#include "assert.h"
 
-void declare_native_rule( const char * module, const char * rule, const char * * args,
- LIST * (*f)( FRAME *, int ), int version )
+#include <assert.h>
+
+
+void declare_native_rule( char const * module, char const * rule,
+ char const * * args, LIST * (*f)( FRAME *, int ), int version )
 {
- OBJECT * module_obj = 0;
- module_t * m;
- if ( module )
- {
- module_obj = object_new( module );
- }
- m = bindmodule( module_obj );
+ OBJECT * const module_obj = module ? object_new( module ) : 0 ;
+ module_t * m = bindmodule( module_obj );
     if ( module_obj )
- {
         object_free( module_obj );
- }
- if (m->native_rules == 0)
- {
- m->native_rules = hashinit( sizeof( native_rule_t ), "native rules");
- }
+ if ( !m->native_rules )
+ m->native_rules = hashinit( sizeof( native_rule_t ), "native rules" );
 
     {
- native_rule_t *np;
- OBJECT * name = object_new( rule );
+ OBJECT * const name = object_new( rule );
         int found;
- np = (native_rule_t *)hash_insert( m->native_rules, name, &found );
+ native_rule_t * const np = (native_rule_t *)hash_insert(
+ m->native_rules, name, &found );
         np->name = name;
         assert( !found );
         np->procedure = function_builtin( f, 0, args );

Modified: branches/release/tools/build/v2/engine/native.h
==============================================================================
--- branches/release/tools/build/v2/engine/native.h (original)
+++ branches/release/tools/build/v2/engine/native.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,37 +1,34 @@
-/* Copyright David Abrahams 2003. 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) */
+/* Copyright 2003. David Abrahams
+ * 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)
+ */
 
 #ifndef NATIVE_H_VP_2003_12_09
 #define NATIVE_H_VP_2003_12_09
 
+#include "function.h"
+#include "frames.h"
 #include "lists.h"
 #include "object.h"
-#include "frames.h"
-#include "function.h"
-#include "rules.h"
 
-struct native_rule_t
+typedef struct native_rule_t
 {
     OBJECT * name;
     FUNCTION * procedure;
- /* Version of the interface that the native rule provides.
- It's possible that we want to change the set parameter
- for existing native rule. In that case, version number
- should be incremented so that Boost.Build can check for
- version it relies on.
 
- Versions are numbered from 1.
+ /* Version of the interface that the native rule provides. It is possible
+ * that we want to change the set parameter for existing native rule. In
+ * that case, version number should be incremented so Boost.Build can check
+ * for the version it relies on.
+ *
+ * Versions are numbered from 1.
     */
     int version;
-};
-
-/* MSVC debugger gets confused unless this is provided */
-typedef struct native_rule_t native_rule_t ;
-
-void declare_native_rule( const char * module, const char * rule, const char * * args,
- LIST * (*f)( FRAME *, int ), int version );
-
+} native_rule_t;
+/* MSVC debugger gets confused unless the native_rule_t typedef is provided. */
 
+void declare_native_rule( char const * module, char const * rule,
+ char const * * args, LIST * (*f)( FRAME *, int ), int version );
 
 #endif

Modified: branches/release/tools/build/v2/engine/object.c
==============================================================================
--- branches/release/tools/build/v2/engine/object.c (original)
+++ branches/release/tools/build/v2/engine/object.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,28 +5,30 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-# include "jam.h"
-# include "object.h"
-# include <stddef.h>
-# include <stdlib.h>
-# include <assert.h>
-
 /*
  * object.c - object manipulation routines
  *
  * External functions:
- *
- * object_new() - create an object from a string
- * object_copy() - return a copy of an object
- * object_free() - free an object
- * object_str() - get the string value of an object
- * object_done() - free string tables
+ * object_new() - create an object from a string
+ * object_new_range() - create an object from a string of given length
+ * object_copy() - return a copy of an object
+ * object_free() - free an object
+ * object_str() - get the string value of an object
+ * object_done() - free string tables
  *
  * This implementation builds a hash table of all strings, so that multiple
  * calls of object_new() on the same string allocate memory for the string once.
  * Strings are never actually freed.
  */
 
+#include "jam.h"
+#include "object.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+
 #define OBJECT_MAGIC 0xa762e0e3u
 
 #ifndef object_copy
@@ -45,10 +47,10 @@
 struct hash_item
 {
     struct hash_header header;
- char data[1];
+ char data[ 1 ];
 };
 
-#define ALLOC_ALIGNMENT ( sizeof( struct hash_item ) - sizeof( struct hash_header ) )
+#define ALLOC_ALIGNMENT (sizeof(struct hash_item) - sizeof(struct hash_header))
 
 typedef struct string_set
 {
@@ -57,10 +59,10 @@
     struct hash_item * * data;
 } string_set;
 
-static string_set strhash;
-static int strtotal = 0;
-static int strcount_in = 0;
-static int strcount_out = 0;
+static string_set strhash;
+static int strtotal = 0;
+static int strcount_in = 0;
+static int strcount_out = 0;
 
 
 /*
@@ -68,11 +70,11 @@
  * down on internal fragmentation.
  */
 
-# define STRING_BLOCK 4096
+#define STRING_BLOCK 4096
 typedef struct strblock
 {
     struct strblock * next;
- char data[STRING_BLOCK];
+ char data[ STRING_BLOCK ];
 } strblock;
 
 static strblock * strblock_chain = 0;
@@ -89,18 +91,18 @@
 static char * allocate( size_t n )
 {
 #ifdef BJAM_NEWSTR_NO_ALLOCATE
- return (char*)BJAM_MALLOC(n);
+ return (char *)BJAM_MALLOC( n );
 #else
     /* See if we can grab storage from an existing block. */
     size_t remaining = storage_finish - storage_start;
- n = ((n + ALLOC_ALIGNMENT - 1) / ALLOC_ALIGNMENT) * ALLOC_ALIGNMENT;
+ n = ( ( n + ALLOC_ALIGNMENT - 1 ) / ALLOC_ALIGNMENT ) * ALLOC_ALIGNMENT;
     if ( remaining >= n )
     {
         char * result = storage_start;
         storage_start += n;
         return result;
     }
- else /* Must allocate a new block. */
+ else /* Must allocate a new block. */
     {
         strblock * new_block;
         size_t nalloc = n;
@@ -108,7 +110,8 @@
             nalloc = STRING_BLOCK;
 
         /* Allocate a new block and link into the chain. */
- new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
+ new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[ 0 ] ) +
+ nalloc * sizeof( new_block->data[ 0 ] ) );
         if ( new_block == 0 )
             return 0;
         new_block->next = strblock_chain;
@@ -125,32 +128,32 @@
 #endif
 }
 
-static unsigned int hash_keyval( const char * key )
+
+static unsigned int hash_keyval( char const * key, int const size )
 {
+ unsigned int const magic = 2147059363;
     unsigned int hash = 0;
- unsigned i;
- unsigned int len = strlen( key );
 
- for ( i = 0; i < len / sizeof( unsigned int ); ++i )
+ unsigned int i;
+ for ( i = 0; i < size / sizeof( unsigned int ); ++i )
     {
         unsigned int val;
         memcpy( &val, key, sizeof( unsigned int ) );
- hash = hash * 2147059363 + val;
+ hash = hash * magic + val;
         key += sizeof( unsigned int );
     }
 
     {
         unsigned int val = 0;
- memcpy( &val, key, len % sizeof( unsigned int ) );
- hash = hash * 2147059363 + val;
+ memcpy( &val, key, size % sizeof( unsigned int ) );
+ hash = hash * magic + val;
     }
 
- hash += (hash >> 17);
-
- return hash;
+ return hash + ( hash >> 17 );
 }
 
-static void string_set_init(string_set * set)
+
+static void string_set_init( string_set * set )
 {
     set->size = 0;
     set->num = 4;
@@ -158,67 +161,68 @@
     memset( set->data, 0, set->num * sizeof( struct hash_item * ) );
 }
 
-static void string_set_done(string_set * set)
+
+static void string_set_done( string_set * set )
 {
     BJAM_FREE( set->data );
 }
 
-static void string_set_resize(string_set *set)
+
+static void string_set_resize( string_set * set )
 {
     unsigned i;
     string_set new_set;
     new_set.num = set->num * 2;
     new_set.size = set->size;
- new_set.data = (struct hash_item * *)BJAM_MALLOC( sizeof( struct hash_item * ) * new_set.num );
- memset(new_set.data, 0, sizeof(struct hash_item *) * new_set.num);
+ new_set.data = (struct hash_item * *)BJAM_MALLOC( sizeof( struct hash_item *
+ ) * new_set.num );
+ memset( new_set.data, 0, sizeof( struct hash_item * ) * new_set.num );
     for ( i = 0; i < set->num; ++i )
     {
- while ( set->data[i] )
+ while ( set->data[ i ] )
         {
- struct hash_item * temp = set->data[i];
+ struct hash_item * temp = set->data[ i ];
             unsigned pos = temp->header.hash % new_set.num;
- set->data[i] = temp->header.next;
- temp->header.next = new_set.data[pos];
- new_set.data[pos] = temp;
+ set->data[ i ] = temp->header.next;
+ temp->header.next = new_set.data[ pos ];
+ new_set.data[ pos ] = temp;
         }
     }
     BJAM_FREE( set->data );
     *set = new_set;
 }
 
-static const char * string_set_insert ( string_set * set, const char * string )
+
+static char const * string_set_insert( string_set * set, char const * string,
+ int const size )
 {
- unsigned hash = hash_keyval( string );
+ unsigned hash = hash_keyval( string, size );
     unsigned pos = hash % set->num;
- unsigned l;
 
     struct hash_item * result;
 
- for ( result = set->data[pos]; result; result = result->header.next )
- {
- if ( strcmp( result->data, string ) == 0 )
- {
+ for ( result = set->data[ pos ]; result; result = result->header.next )
+ if ( !strncmp( result->data, string, size ) && !result->data[ size ] )
             return result->data;
- }
- }
 
- if( set->size >= set->num )
+ if ( set->size >= set->num )
     {
         string_set_resize( set );
         pos = hash % set->num;
     }
 
- l = strlen( string );
- result = (struct hash_item *)allocate( sizeof( struct hash_header ) + l + 1 );
+ result = (struct hash_item *)allocate( sizeof( struct hash_header ) + size +
+ 1 );
     result->header.hash = hash;
- result->header.next = set->data[pos];
+ result->header.next = set->data[ pos ];
 #ifndef NDEBUG
     result->header.magic = OBJECT_MAGIC;
 #endif
- memcpy( result->data, string, l + 1 );
- assert( hash_keyval( result->data ) == result->header.hash );
- set->data[pos] = result;
- strtotal += l + 1;
+ memcpy( result->data, string, size );
+ result->data[ size ] = '\0';
+ assert( hash_keyval( result->data, size ) == result->header.hash );
+ set->data[ pos ] = result;
+ strtotal += size + 1;
     ++set->size;
 
     return result->data;
@@ -227,40 +231,54 @@
 
 static struct hash_item * object_get_item( OBJECT * obj )
 {
- return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data ) );
+ return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data
+ ) );
 }
 
 
 static void object_validate( OBJECT * obj )
 {
+ assert( obj );
     assert( object_get_item( obj )->header.magic == OBJECT_MAGIC );
 }
 
 
 /*
- * object_new() - create an object from a string.
+ * object_new_range() - create an object from a string of given length
  */
 
-OBJECT * object_new( const char * string )
+OBJECT * object_new_range( char const * const string, int const size )
 {
-#ifdef BJAM_NO_MEM_CACHE
- int l = strlen( string );
- struct hash_item * m = (struct hash_item *)BJAM_MALLOC( sizeof(struct hash_header) + l + 1 );
+ ++strcount_in;
 
- strtotal += l + 1;
- memcpy( m->data, string, l + 1 );
- m->header.magic = OBJECT_MAGIC;
- return (OBJECT *)m->data;
+#ifdef BJAM_NO_MEM_CACHE
+ {
+ struct hash_item * const m = (struct hash_item *)BJAM_MALLOC( sizeof(
+ struct hash_header ) + size + 1 );
+ strtotal += size + 1;
+ memcpy( m->data, string, size );
+ m->data[ size ] = '\0';
+ m->header.magic = OBJECT_MAGIC;
+ return (OBJECT *)m->data;
+ }
 #else
- if ( ! strhash.data )
+ if ( !strhash.data )
         string_set_init( &strhash );
+ return (OBJECT *)string_set_insert( &strhash, string, size );
+#endif
+}
 
- strcount_in += 1;
 
- return (OBJECT *)string_set_insert( &strhash, string );
-#endif
+/*
+ * object_new() - create an object from a string
+ */
+
+OBJECT * object_new( char const * const string )
+{
+ return object_new_range( string, strlen( string ) );
 }
 
+
 #ifndef object_copy
 
 /*
@@ -273,7 +291,7 @@
 #ifdef BJAM_NO_MEM_CACHE
     return object_new( object_str( obj ) );
 #else
- strcount_in += 1;
+ ++strcount_in;
     return obj;
 #endif
 }
@@ -289,18 +307,18 @@
 #ifdef BJAM_NO_MEM_CACHE
     BJAM_FREE( object_get_item( obj ) );
 #endif
- strcount_out += 1;
+ ++strcount_out;
 }
 
 
 /*
- * object_str() - return the
+ * object_str() - return the OBJECT's internal C string
  */
 
-const char * object_str( OBJECT * obj )
+char const * object_str( OBJECT * obj )
 {
     object_validate( obj );
- return (const char *)obj;
+ return (char const *)obj;
 }
 
 
@@ -313,9 +331,9 @@
     object_validate( lhs );
     object_validate( rhs );
 #ifdef BJAM_NO_MEM_CACHE
- return strcmp(object_str(lhs), object_str(rhs)) == 0;
+ return !strcmp( object_str( lhs ), object_str( rhs ) );
 #else
- assert( (lhs == rhs) == ( strcmp(object_str(lhs), object_str(rhs)) == 0 ) );
+ assert( ( lhs == rhs ) == !strcmp( object_str( lhs ), object_str( rhs ) ) );
     return lhs == rhs;
 #endif
 }
@@ -329,7 +347,7 @@
 {
     object_validate( obj );
 #ifdef BJAM_NO_MEM_CACHE
- return hash_keyval( object_str( obj ) );
+ return hash_keyval( object_str( obj ), strlen( object_str( obj ) ) );
 #else
     return object_get_item( obj )->header.hash;
 #endif
@@ -343,37 +361,34 @@
 
 void object_done()
 {
-
 #ifdef BJAM_NEWSTR_NO_ALLOCATE
-
     unsigned i;
-
     for ( i = 0; i < strhash.num; ++i )
     {
- while ( strhash.data[i] )
+ while ( strhash.data[ i ] )
         {
- struct hash_item * item = strhash.data[i];
- strhash.data[i] = item->header.next;
+ struct hash_item * item = strhash.data[ i ];
+ strhash.data[ i ] = item->header.next;
             BJAM_FREE( item );
         }
     }
-
 #else
-
     /* Reclaim string blocks. */
- while ( strblock_chain != 0 )
+ while ( strblock_chain )
     {
- strblock * n = strblock_chain->next;
- BJAM_FREE(strblock_chain);
+ strblock * const n = strblock_chain->next;
+ BJAM_FREE( strblock_chain );
         strblock_chain = n;
     }
-
 #endif
 
     string_set_done( &strhash );
 
     if ( DEBUG_MEM )
+ {
         printf( "%dK in strings\n", strtotal / 1024 );
-
- /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
+ if ( strcount_in != strcount_out )
+ printf( "--- %d strings of %d dangling\n", strcount_in -
+ strcount_out, strcount_in );
+ }
 }

Modified: branches/release/tools/build/v2/engine/object.h
==============================================================================
--- branches/release/tools/build/v2/engine/object.h (original)
+++ branches/release/tools/build/v2/engine/object.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -13,8 +13,9 @@
 
 typedef struct _object OBJECT;
 
-OBJECT * object_new ( const char * );
-void object_done ( void );
+OBJECT * object_new( char const * const );
+OBJECT * object_new_range( char const * const, int const size );
+void object_done( void );
 
 #if defined(NDEBUG) && !defined(BJAM_NO_MEM_CACHE)
 
@@ -24,19 +25,19 @@
     struct hash_item * next;
 };
 
-#define object_str( obj ) ( (const char *)( obj ) )
-#define object_copy( obj ) ( obj )
-#define object_free( obj ) ( (void)0 )
-#define object_equal( lhs, rhs ) ( ( lhs ) == ( rhs ) )
-#define object_hash( obj ) ( ((struct hash_header *)( (char *)( obj ) - sizeof(struct hash_header) ))->hash )
+#define object_str( obj ) ((char const *)(obj))
+#define object_copy( obj ) (obj)
+#define object_free( obj ) ((void)0)
+#define object_equal( lhs, rhs ) ((lhs) == (rhs))
+#define object_hash( obj ) (((struct hash_header *)((char *)(obj) - sizeof(struct hash_header)))->hash)
 
 #else
 
-const char * object_str ( OBJECT * );
-OBJECT * object_copy ( OBJECT * );
-void object_free ( OBJECT * );
-int object_equal ( OBJECT *, OBJECT * );
-unsigned int object_hash ( OBJECT * );
+char const * object_str ( OBJECT * );
+OBJECT * object_copy ( OBJECT * );
+void object_free ( OBJECT * );
+int object_equal( OBJECT *, OBJECT * );
+unsigned int object_hash ( OBJECT * );
 
 #endif
 

Modified: branches/release/tools/build/v2/engine/option.h
==============================================================================
--- branches/release/tools/build/v2/engine/option.h (original)
+++ branches/release/tools/build/v2/engine/option.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -13,11 +13,11 @@
 
 typedef struct bjam_option
 {
- char flag; /* filled in by getoption() */
- char *val; /* set to random address if true */
+ char flag; /* filled in by getoption() */
+ char * val; /* set to random address if true */
 } bjam_option;
 
-# define N_OPTS 256
+#define N_OPTS 256
 
-int getoptions( int argc, char **argv, char *opts, bjam_option *optv );
-char * getoptval( bjam_option *optv, char opt, int subopt );
+int getoptions( int argc, char * * argv, char * opts, bjam_option * optv );
+char * getoptval( bjam_option * optv, char opt, int subopt );

Modified: branches/release/tools/build/v2/engine/output.c
==============================================================================
--- branches/release/tools/build/v2/engine/output.c (original)
+++ branches/release/tools/build/v2/engine/output.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,22 +6,19 @@
 
 #include "jam.h"
 #include "output.h"
-#include "object.h"
+
 #include <stdio.h>
 
+
 #define bjam_out (stdout)
 #define bjam_err (stderr)
 
-static void out_
-(
- char const * data,
- FILE * io
-)
+static void out_( char const * data, FILE * const io )
 {
     while ( *data )
     {
- size_t len = strcspn(data,"\r");
- data += fwrite(data,1,len,io);
+ size_t const len = strcspn( data, "\r" );
+ data += fwrite( data, 1, len, io );
         if ( *data == '\r' ) ++data;
     }
 }
@@ -29,21 +26,19 @@
 
 void out_action
 (
- char const * action,
- char const * target,
- char const * command,
- char const * out_data,
- char const * err_data,
- int exit_reason
+ char const * const action,
+ char const * const target,
+ char const * const command,
+ char const * const out_data,
+ char const * const err_data,
+ int const exit_reason
 )
 {
- /* Print out the action+target line, if the action is quite the action
+ /* Print out the action + target line, if the action is quiet the action
      * should be null.
      */
     if ( action )
- {
         fprintf( bjam_out, "%s %s\n", action, target );
- }
 
     /* Print out the command executed if given -d+2. */
     if ( DEBUG_EXEC )
@@ -54,45 +49,25 @@
 
     /* Print out the command executed to the command stream. */
     if ( globs.cmdout )
- {
         fputs( command, globs.cmdout );
- }
 
- switch ( exit_reason )
- {
- case EXIT_OK:
- break;
- case EXIT_FAIL:
- break;
- case EXIT_TIMEOUT:
- {
- /* Process expired, make user aware with explicit message. */
- if ( action )
- {
- /* But only output for non-quietly actions. */
- fprintf( bjam_out, "%ld second time limit exceeded\n", globs.timeout );
- }
- break;
- }
- default:
- break;
- }
+ /* If the process expired, make user aware with an explicit message, but do
+ * this only for non-quiet actions.
+ */
+ if ( exit_reason == EXIT_TIMEOUT && action )
+ fprintf( bjam_out, "%ld second time limit exceeded\n", globs.timeout );
 
- /* Print out the command output, if requested, or if the program failed. */
- if ( action || exit_reason != EXIT_OK)
+ /* Print out the command output, if requested, or if the program failed, but
+ * only output for non-quiet actions.
+ */
+ if ( action || exit_reason != EXIT_OK )
     {
- /* But only output for non-quietly actions. */
- if ( ( 0 != out_data ) &&
+ if ( out_data &&
            ( ( globs.pipe_action & 1 /* STDOUT_FILENO */ ) ||
              ( globs.pipe_action == 0 ) ) )
- {
             out_( out_data, bjam_out );
- }
- if ( ( 0 != err_data ) &&
- ( globs.pipe_action & 2 /* STDERR_FILENO */ ) )
- {
+ if ( err_data && ( globs.pipe_action & 2 /* STDERR_FILENO */ ) )
             out_( err_data, bjam_err );
- }
     }
 
     fflush( bjam_out );
@@ -101,25 +76,23 @@
 }
 
 
-OBJECT * outf_int( int value )
+OBJECT * outf_int( int const value )
 {
- char buffer[50];
+ char buffer[ 50 ];
     sprintf( buffer, "%i", value );
     return object_new( buffer );
 }
 
 
-OBJECT * outf_double( double value )
+OBJECT * outf_double( double const value )
 {
- char buffer[50];
+ char buffer[ 50 ];
     sprintf( buffer, "%f", value );
     return object_new( buffer );
 }
 
 
-OBJECT * outf_time( time_t value )
+OBJECT * outf_time( timestamp const * const time )
 {
- char buffer[50];
- strftime( buffer, 49, "%Y-%m-%d %H:%M:%SZ", gmtime( &value ) );
- return object_new( buffer );
+ return object_new( timestamp_str( time ) );
 }

Modified: branches/release/tools/build/v2/engine/output.h
==============================================================================
--- branches/release/tools/build/v2/engine/output.h (original)
+++ branches/release/tools/build/v2/engine/output.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,23 +8,23 @@
 #define BJAM_OUTPUT_H
 
 #include "object.h"
-#include <time.h>
+#include "timestamp.h"
 
 #define EXIT_OK 0
 #define EXIT_FAIL 1
 #define EXIT_TIMEOUT 2
 
 void out_action(
- const char * action,
- const char * target,
- const char * command,
- const char * out_data,
- const char * err_data,
- int exit_reason
- );
+ char const * const action,
+ char const * const target,
+ char const * const command,
+ char const * const out_data,
+ char const * const err_data,
+ int const exit_reason
+);
 
-OBJECT * outf_int( int value );
-OBJECT * outf_double( double value );
-OBJECT * outf_time( time_t value );
+OBJECT * outf_int( int const value );
+OBJECT * outf_double( double const value );
+OBJECT * outf_time( timestamp const * const value );
 
 #endif

Modified: branches/release/tools/build/v2/engine/parse.c
==============================================================================
--- branches/release/tools/build/v2/engine/parse.c (original)
+++ branches/release/tools/build/v2/engine/parse.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -94,7 +94,7 @@
     }
     else
     {
- yyinput_stream( &p->file, &p->line );
+ yyinput_last_read_token( &p->file, &p->line );
         p->file = object_copy( p->file );
     }
 

Modified: branches/release/tools/build/v2/engine/parse.h
==============================================================================
--- branches/release/tools/build/v2/engine/parse.h (original)
+++ branches/release/tools/build/v2/engine/parse.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,16 +10,17 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
+/*
+ * parse.h - make and destroy parse trees as driven by the parser.
+ */
+
 #ifndef PARSE_DWA20011020_H
 #define PARSE_DWA20011020_H
 
 #include "frames.h"
-#include "modules.h"
 #include "lists.h"
+#include "modules.h"
 
-/*
- * parse.h - make and destroy parse trees as driven by the parser.
- */
 
 #define PARSE_APPEND 0
 #define PARSE_FOREACH 1
@@ -41,10 +42,13 @@
 #define PARSE_SWITCH 17
 #define PARSE_WHILE 18
 
+
 /*
  * Parse tree node.
  */
 
+typedef struct _PARSE PARSE;
+
 struct _PARSE {
     int type;
     PARSE * left;
@@ -59,20 +63,14 @@
     int line;
 };
 
-void parse_file( OBJECT *, FRAME * );
-void parse_save( PARSE * );
+void parse_file( OBJECT *, FRAME * );
+void parse_save( PARSE * );
 
-PARSE * parse_make(
- int type,
- PARSE * left,
- PARSE * right,
- PARSE * third,
- OBJECT * string,
- OBJECT * string1,
- int num );
+PARSE * parse_make( int type, PARSE * left, PARSE * right, PARSE * third,
+ OBJECT * string, OBJECT * string1, int num );
 
-void parse_refer ( PARSE * );
-void parse_free ( PARSE * );
+void parse_refer( PARSE * );
+void parse_free( PARSE * );
 LIST * parse_evaluate( PARSE *, FRAME * );
 
 #endif

Modified: branches/release/tools/build/v2/engine/patchlevel.h
==============================================================================
--- branches/release/tools/build/v2/engine/patchlevel.h (original)
+++ branches/release/tools/build/v2/engine/patchlevel.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,9 +9,9 @@
 
 #define VERSION_MAJOR 2011
 #define VERSION_MINOR 12
-#define VERSION_PATCH 0
+#define VERSION_PATCH 1
 #define VERSION_MAJOR_SYM "2011"
 #define VERSION_MINOR_SYM "12"
-#define VERSION_PATCH_SYM "00"
-#define VERSION "2011.12"
+#define VERSION_PATCH_SYM "01"
+#define VERSION "2011.12.1"
 #define JAMVERSYM "JAMVERSION=2011.12"

Copied: branches/release/tools/build/v2/engine/pathnt.c (from r80278, /trunk/tools/build/v2/engine/pathnt.c)
==============================================================================
--- /trunk/tools/build/v2/engine/pathnt.c (original)
+++ branches/release/tools/build/v2/engine/pathnt.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -36,6 +36,7 @@
 {
     OBJECT * path;
     OBJECT * key;
+ int exists;
 } path_key_entry;
 
 static struct hash * path_key_cache;
@@ -84,23 +85,24 @@
  * - path_key_cache path/key mapping cache object already initialized
  */
 
-static void canonicWindowsPath( char const * const path, int const path_length,
+static int canonicWindowsPath( char const * const path, int const path_length,
     string * const out )
 {
     char const * last_element;
     unsigned long saved_size;
     char const * p;
+ int missing_parent;
 
     /* This is only called via path_key(), which initializes the cache. */
     assert( path_key_cache );
 
     if ( !path_length )
- return;
+ return 1;
 
     if ( path_length == 1 && path[ 0 ] == '\\' )
     {
         string_push_back( out, '\\' );
- return;
+ return 1;
     }
 
     if ( path[ 1 ] == ':' &&
@@ -110,7 +112,7 @@
         string_push_back( out, toupper( path[ 0 ] ) );
         string_push_back( out, ':' );
         string_push_back( out, '\\' );
- return;
+ return 1;
     }
 
     /* Find last '\\'. */
@@ -122,6 +124,8 @@
         p == path + 2 && path[ 1 ] == ':' )
         ++p;
 
+ missing_parent = 0;
+
     if ( p >= path )
     {
         char const * const dir = path;
@@ -133,7 +137,10 @@
         if ( !found )
         {
             result->path = dir_obj;
- canonicWindowsPath( dir, dir_length, out );
+ if ( canonicWindowsPath( dir, dir_length, out ) )
+ result->exists = 1;
+ else
+ result->exists = 0;
             result->key = object_new( out->value );
         }
         else
@@ -141,6 +148,8 @@
             object_free( dir_obj );
             string_append( out, object_str( result->key ) );
         }
+ if ( !result->exists )
+ missing_parent = 1;
     }
 
     if ( out->size && out->value[ out->size - 1 ] != '\\' )
@@ -149,6 +158,7 @@
     saved_size = out->size;
     string_append_range( out, last_element, path + path_length );
 
+ if ( !missing_parent )
     {
         char const * const n = last_element;
         int const n_length = path + path_length - n;
@@ -162,9 +172,11 @@
                 string_truncate( out, saved_size );
                 string_append( out, fd.cFileName );
                 FindClose( hf );
+ return 1;
             }
         }
     }
+ return 0;
 }
 
 
@@ -236,8 +248,11 @@
             {
                 string canonic_path[ 1 ];
                 string_new( canonic_path );
- canonicWindowsPath( object_str( normalized ), normalized_size,
- canonic_path );
+ if ( canonicWindowsPath( object_str( normalized ), normalized_size,
+ canonic_path ) )
+ nresult->exists = 1;
+ else
+ nresult->exists = 0;
                 nresult->key = object_new( canonic_path->value );
                 string_free( canonic_path );
             }
@@ -248,6 +263,7 @@
         {
             result->path = object_copy( path );
             result->key = object_copy( nresult->key );
+ result->exists = nresult->exists;
         }
     }
 

Modified: branches/release/tools/build/v2/engine/pathsys.h
==============================================================================
--- branches/release/tools/build/v2/engine/pathsys.h (original)
+++ branches/release/tools/build/v2/engine/pathsys.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,86 +11,74 @@
 /*
  * PATHNAME - a name of a file, broken into <grist>dir/base/suffix(member)
  *
- * <grist> is salt to distinguish between targets that otherwise would
- * have the same name: it never appears in the bound name of a target.
- * (member) is an archive member name: the syntax is arbitrary, but must
- * agree in path_parse(), path_build() and the Jambase.
+ * <grist> - salt to distinguish between targets that would otherwise have the
+ * same name - it never appears in the bound name of a target.
+ *
+ * (member) - archive member name: the syntax is arbitrary, but must agree in
+ * path_parse(), path_build() and the Jambase.
  */
 
 #ifndef PATHSYS_VP_20020211_H
-# define PATHSYS_VP_20020211_H
+#define PATHSYS_VP_20020211_H
 
-#include "jam.h"
-#include "strings.h"
 #include "object.h"
+#include "strings.h"
 
-typedef struct _pathname PATHNAME;
-typedef struct _pathpart PATHPART;
 
-struct _pathpart
+typedef struct _pathpart
 {
- const char * ptr;
- int len;
-};
+ char const * ptr;
+ int len;
+} PATHPART;
 
-struct _pathname
+typedef struct _pathname
 {
- PATHPART part[6];
-
-#define f_grist part[0]
-#define f_root part[1]
-#define f_dir part[2]
-#define f_base part[3]
-#define f_suffix part[4]
-#define f_member part[5]
-};
-
-void path_build( PATHNAME * f, string * file, int binding );
-void path_build1( PATHNAME * f, string * file );
-
-void path_parse( const char * file, PATHNAME * f );
-void path_parent( PATHNAME * f );
-
-#ifdef NT
-
-/** Returns object_new-allocated string with long equivivalent of 'short_name'.
- If none exists -- i.e. 'short_path' is already long path, it's returned
- unaltered. */
-OBJECT * short_path_to_long_path( OBJECT * short_path );
-
-#endif
+ PATHPART part[ 6 ];
 
-/** Given a path, returns an object that can be
- used as a unique key for that path. Equivalent
- paths such as a/b, A\B, and a\B on NT all yield the
- same key.
+#define f_grist part[ 0 ]
+#define f_root part[ 1 ]
+#define f_dir part[ 2 ]
+#define f_base part[ 3 ]
+#define f_suffix part[ 4 ]
+#define f_member part[ 5 ]
+} PATHNAME;
+
+
+void path_build( PATHNAME *, string * file );
+void path_parse( char const * file, PATHNAME * );
+void path_parent( PATHNAME * );
+
+/* Given a path, returns an object containing an equivalent path in canonical
+ * format that can be used as a unique key for that path. Equivalent paths such
+ * as a/b, A\B, and a\B on NT all yield the same key.
  */
 OBJECT * path_as_key( OBJECT * path );
-void path_add_key( OBJECT * path );
 
-#ifdef USE_PATHUNIX
-/** Returns a static pointer to the system dependent path to the temporary
- directory. NOTE: *without* a trailing path separator.
-*/
-const char * path_tmpdir( void );
+/* Called as an optimization when we know we have a path that is already in its
+ * canonical/long/key form. Avoids the need for some subsequent path_as_key()
+ * call to do a potentially expensive path conversion requiring access to the
+ * actual underlying file system.
+ */
+void path_register_key( OBJECT * canonic_path );
+
+/* Returns a static pointer to the system dependent path to the temporary
+ * directory. NOTE: Does *not* include a trailing path separator.
+ */
+string const * path_tmpdir( void );
 
-/** Returns a new temporary name.
-*/
+/* Returns a new temporary name. */
 OBJECT * path_tmpnam( void );
 
-/** Returns a new temporary path.
-*/
+/* Returns a new temporary path. */
 OBJECT * path_tmpfile( void );
-#endif
 
-/** Give the first argument to 'main', return a full path to
- our executable. Returns null in the unlikely case it
- cannot be determined. Caller is responsible for freeing
- the string.
-
- Implemented in jam.c
-*/
-char * executable_path (const char *argv0);
+/* Give the first argument to 'main', return a full path to our executable.
+ * Returns null in the unlikely case it cannot be determined. Caller is
+ * responsible for freeing the string.
+ *
+ * Implemented in jam.c
+ */
+char * executable_path( char const * argv0 );
 
 void path_done( void );
 

Modified: branches/release/tools/build/v2/engine/pathunix.c
==============================================================================
--- branches/release/tools/build/v2/engine/pathunix.c (original)
+++ branches/release/tools/build/v2/engine/pathunix.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,584 +4,68 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Copyright 2005 Rene Rivera.
- * 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)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-# include "strings.h"
-# include "object.h"
-# include "filesys.h"
-# include <time.h>
-# include <stdlib.h>
-# include <assert.h>
-# ifndef OS_NT
-# include <unistd.h>
-# endif
-
-# ifdef USE_PATHUNIX
-
-/*
- * pathunix.c - manipulate file names on UNIX, NT, OS2, AmigaOS
- *
- * External routines:
- *
- * path_parse() - split a file name into dir/base/suffix/member
- * path_build() - build a filename given dir/base/suffix/member
- * path_parent() - make a PATHNAME point to its parent dir
- *
- * File_parse() and path_build() just manipuate a string and a structure;
- * they do not make system calls.
- *
- * 04/08/94 (seiwald) - Coherent/386 support added.
- * 12/26/93 (seiwald) - handle dir/.suffix properly in path_build()
- * 12/19/94 (mikem) - solaris string table insanity support
- * 12/21/94 (wingerd) Use backslashes for pathnames - the NT way.
- * 02/14/95 (seiwald) - parse and build /xxx properly
- * 02/23/95 (wingerd) Compilers on NT can handle "/" in pathnames, so we
- * should expect hdr searches to come up with strings
- * like "thing/thing.h". So we need to test for "/" as
- * well as "\" when parsing pathnames.
- * 03/16/95 (seiwald) - fixed accursed typo on line 69.
- * 05/03/96 (seiwald) - split from filent.c, fileunix.c
- * 12/20/96 (seiwald) - when looking for the rightmost . in a file name,
- * don't include the archive member name.
- * 01/13/01 (seiwald) - turn on \ handling on UNIX, on by accident
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * Copyright 2005 Rene Rivera.
+ * 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)
  */
 
 /*
- * path_parse() - split a file name into dir/base/suffix/member
+ * pathunix.c - UNIX specific path manipulation support
  */
 
-void path_parse( const char * file, PATHNAME * f )
-{
- const char * p;
- const char * q;
- const char * end;
-
- memset( (char *)f, 0, sizeof( *f ) );
-
- /* Look for <grist> */
-
- if ( ( file[0] == '<' ) && ( p = strchr( file, '>' ) ) )
- {
- f->f_grist.ptr = file;
- f->f_grist.len = p - file;
- file = p + 1;
- }
-
- /* Look for dir/ */
-
- p = strrchr( file, '/' );
-
-# if PATH_DELIM == '\\'
- /* On NT, look for dir\ as well */
- {
- char *p1 = strrchr( file, '\\' );
- p = p1 > p ? p1 : p;
- }
-# endif
-
- if ( p )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p - file;
-
- /* Special case for / - dirname is /, not "" */
-
- if ( !f->f_dir.len )
- f->f_dir.len = 1;
-
-# if PATH_DELIM == '\\'
- /* Special case for D:/ - dirname is D:/, not "D:" */
-
- if ( f->f_dir.len == 2 && file[1] == ':' )
- f->f_dir.len = 3;
-# endif
-
- file = p + 1;
- }
-
- end = file + strlen( file );
-
- /* Look for (member) */
-
- if ( ( p = strchr( file, '(' ) ) && ( end[ -1 ] == ')' ) )
- {
- f->f_member.ptr = p + 1;
- f->f_member.len = end - p - 2;
- end = p;
- }
-
- /* Look for .suffix */
- /* This would be memrchr() */
-
- p = 0;
- q = file;
-
- while ( ( q = (char *)memchr( q, '.', end - q ) ) )
- p = q++;
+#include "pathsys.h"
 
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
+#include <stdlib.h>
+#include <unistd.h> /* needed for getpid() */
 
- /* Leaves base */
-
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-}
 
 /*
- * path_delims - the string of legal path delimiters
+ * path_get_process_id_()
  */
-static char path_delims[] = {
- PATH_DELIM,
-# if PATH_DELIM == '\\'
- '/',
-# endif
- 0
-};
 
-/*
- * is_path_delim() - true iff c is a path delimiter
- */
-static int is_path_delim( char c )
+unsigned long path_get_process_id_( void )
 {
- char* p = strchr( path_delims, c );
- return p && *p;
+ return getpid();
 }
 
-/*
- * as_path_delim() - convert c to a path delimiter if it isn't one
- * already
- */
-static char as_path_delim( char c )
-{
- return is_path_delim( c ) ? c : PATH_DELIM;
-}
 
 /*
- * path_build() - build a filename given dir/base/suffix/member
- *
- * To avoid changing slash direction on NT when reconstituting paths,
- * instead of unconditionally appending PATH_DELIM we check the
- * past-the-end character of the previous path element. If it is in
- * path_delims, we append that, and only append PATH_DELIM as a last
- * resort. This heuristic is based on the fact that PATHNAME objects
- * are usually the result of calling path_parse, which leaves the
- * original slashes in the past-the-end position. Correctness depends
- * on the assumption that all strings are zero terminated, so a
- * past-the-end character will always be available.
- *
- * As an attendant patch, we had to ensure that backslashes are used
- * explicitly in timestamp.c
+ * path_get_temp_path_()
  */
 
-void
-path_build(
- PATHNAME *f,
- string *file,
- int binding )
+void path_get_temp_path_( string * buffer )
 {
- file_build1( f, file );
-
- /* Don't prepend root if it's . or directory is rooted */
-# if PATH_DELIM == '/'
-
- if ( f->f_root.len
- && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
- && !( f->f_dir.len && f->f_dir.ptr[0] == '/' ) )
-
-# else /* unix */
-
- if ( f->f_root.len
- && !( f->f_root.len == 1 && f->f_root.ptr[0] == '.' )
- && !( f->f_dir.len && f->f_dir.ptr[0] == '/' )
- && !( f->f_dir.len && f->f_dir.ptr[0] == '\\' )
- && !( f->f_dir.len && f->f_dir.ptr[1] == ':' ) )
-
-# endif /* unix */
-
- {
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- /* If 'root' already ends with path delimeter,
- don't add yet another one. */
- if ( ! is_path_delim( f->f_root.ptr[f->f_root.len-1] ) )
- string_push_back( file, as_path_delim( f->f_root.ptr[f->f_root.len] ) );
- }
-
- if ( f->f_dir.len )
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
-
- /* UNIX: Put / between dir and file */
- /* NT: Put \ between dir and file */
-
- if ( f->f_dir.len && ( f->f_base.len || f->f_suffix.len ) )
- {
- /* UNIX: Special case for dir \ : don't add another \ */
- /* NT: Special case for dir / : don't add another / */
-
-# if PATH_DELIM == '\\'
- if ( !( f->f_dir.len == 3 && f->f_dir.ptr[1] == ':' ) )
-# endif
- if ( !( f->f_dir.len == 1 && is_path_delim( f->f_dir.ptr[0] ) ) )
- string_push_back( file, as_path_delim( f->f_dir.ptr[f->f_dir.len] ) );
- }
-
- if ( f->f_base.len )
- {
- string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
- }
-
- if ( f->f_suffix.len )
- {
- string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
- }
-
- if ( f->f_member.len )
- {
- string_push_back( file, '(' );
- string_append_range( file, f->f_member.ptr, f->f_member.ptr + f->f_member.len );
- string_push_back( file, ')' );
- }
+ char const * t = getenv( "TMPDIR" );
+ string_append( buffer, t ? t : "/tmp" );
 }
 
+
 /*
- * path_parent() - make a PATHNAME point to its parent dir
+ * path_register_key()
  */
 
-void
-path_parent( PATHNAME *f )
-{
- /* just set everything else to nothing */
-
- f->f_base.ptr =
- f->f_suffix.ptr =
- f->f_member.ptr = "";
-
- f->f_base.len =
- f->f_suffix.len =
- f->f_member.len = 0;
-}
-
-#ifdef NT
-#include <windows.h>
-
-/* The definition of this in winnt.h is not ANSI-C compatible. */
-#undef INVALID_FILE_ATTRIBUTES
-#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
-
-OBJECT * path_as_key( OBJECT * path );
-static void path_write_key( char * path_, string * out );
-
-void ShortPathToLongPath( char * short_path, string * out )
+void path_register_key( OBJECT * path )
 {
- const char * new_element;
- unsigned long saved_size;
- char * p;
-
- if ( short_path[0] == '\0' )
- {
- return;
- }
-
- if ( short_path[0] == '\\' && short_path[1] == '\0')
- {
- string_push_back( out, '\\' );
- return;
- }
-
- if ( short_path[1] == ':' &&
- ( short_path[2] == '\0' ||
- ( short_path[2] == '\\' && short_path[3] == '\0' ) ) )
- {
- string_push_back( out, toupper( short_path[0] ) );
- string_push_back( out, ':' );
- string_push_back( out, '\\' );
- return;
- }
-
- /* '/' already handled. */
- if ( ( p = strrchr( short_path, '\\' ) ) )
- {
- char saved;
- new_element = p + 1;
-
- /* special case \ */
- if ( p == short_path )
- ++p;
-
- /* special case D:\ */
- if ( p == short_path + 2 && short_path[1] == ':' )
- ++p;
-
- saved = *p;
- *p = '\0';
- path_write_key( short_path, out );
- *p = saved;
- }
- else
- {
- new_element = short_path;
- }
-
- if ( out->size && out->value[ out->size - 1 ] != '\\' )
- {
- string_push_back( out, '\\' );
- }
-
- saved_size = out->size;
- string_append( out, new_element );
-
- if ( ! ( new_element[0] == '.' && new_element[1] == '\0' ||
- new_element[0] == '.' && new_element[1] == '.'
- && new_element[2] == '\0' ) )
- {
- WIN32_FIND_DATA fd;
- HANDLE hf = 0;
- hf = FindFirstFile( out->value, &fd );
-
- /* If the file exists, replace the name. */
- if ( hf != INVALID_HANDLE_VALUE )
- {
- string_truncate( out, saved_size );
- string_append( out, fd.cFileName );
- FindClose( hf );
- }
- }
 }
 
-OBJECT * short_path_to_long_path( OBJECT * short_path )
-{
- return path_as_key( short_path );
-}
-
-struct path_key_entry
-{
- OBJECT * path;
- OBJECT * key;
-};
-
-static struct hash * path_key_cache;
 
-static void path_write_key( char * path_, string * out )
-{
- struct path_key_entry * result;
- OBJECT * path = object_new( path_ );
- int found;
-
- /* This is only called by path_as_key, which initializes the cache. */
- assert( path_key_cache );
-
- result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
- if ( !found )
- {
- /* path_ is already normalized. */
- result->path = path;
- ShortPathToLongPath( path_, out );
- result->key = object_new( out->value );
- }
- else
- {
- object_free( path );
- string_append( out, object_str( result->key ) );
- }
-
-}
-
-static void normalize_path( string * path )
-{
- char * s;
- for ( s = path->value; s < path->value + path->size; ++s )
- {
- if ( *s == '/' )
- *s = '\\';
- else
- *s = tolower( *s );
- }
- /* Strip trailing "/" */
- if ( path->size != 0 && path->size != 3 && path->value[ path->size - 1 ] == '\\' )
- {
- string_pop_back( path );
- }
-}
-
-void path_add_key( OBJECT * path )
-{
- struct path_key_entry * result;
- int found;
-
- if ( ! path_key_cache )
- path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
-
- result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
- if ( !found )
- {
- string buf[1];
- OBJECT * normalized;
- struct path_key_entry * nresult;
- result->path = path;
- string_copy( buf, object_str( path ) );
- normalize_path( buf );
- normalized = object_new( buf->value );
- string_free( buf );
- nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
- if ( !found || nresult == result )
- {
- nresult->path = object_copy( normalized );
- nresult->key = object_copy( path );
- }
- object_free( normalized );
- if ( nresult != result )
- {
- result->path = object_copy( path );
- result->key = object_copy( nresult->key );
- }
- }
-}
-
-OBJECT * path_as_key( OBJECT * path )
-{
- struct path_key_entry * result;
- int found;
-
- if ( ! path_key_cache )
- path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
-
- result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
- if ( !found )
- {
- string buf[1];
- OBJECT * normalized;
- struct path_key_entry * nresult;
- result->path = path;
- string_copy( buf, object_str( path ) );
- normalize_path( buf );
- normalized = object_new( buf->value );
- nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
- if ( !found || nresult == result )
- {
- string long_path[1];
- nresult->path = normalized;
- string_new( long_path );
- ShortPathToLongPath( buf->value, long_path );
- nresult->path = object_copy( normalized );
- nresult->key = object_new( long_path->value );
- string_free( long_path );
- }
- string_free( buf );
- object_free( normalized );
- if ( nresult != result )
- {
- result->path = object_copy( path );
- result->key = object_copy( nresult->key );
- }
- }
-
- return object_copy( result->key );
-}
-
-static void free_path_key_entry( void * xentry, void * data )
-{
- struct path_key_entry * entry = (struct path_key_entry *)xentry;
- object_free( entry->path );
- object_free( entry->key );
-}
-
-void path_done( void )
-{
- if ( path_key_cache )
- {
- hashenumerate( path_key_cache, &free_path_key_entry, (void *)0 );
- hashdone( path_key_cache );
- }
-}
-
-#else
-
-void path_add_key( OBJECT * path )
-{
-}
+/*
+ * path_as_key()
+ */
 
 OBJECT * path_as_key( OBJECT * path )
 {
     return object_copy( path );
 }
 
-void path_done( void )
-{
-}
 
-#endif
-
-static string path_tmpdir_buffer[1];
-static const char * path_tmpdir_result = 0;
-
-const char * path_tmpdir()
-{
- if (!path_tmpdir_result)
- {
- # ifdef OS_NT
- DWORD pathLength = 0;
- pathLength = GetTempPath(pathLength,NULL);
- string_new(path_tmpdir_buffer);
- string_reserve(path_tmpdir_buffer,pathLength);
- pathLength = GetTempPathA(pathLength,path_tmpdir_buffer[0].value);
- path_tmpdir_buffer[0].value[pathLength-1] = '\0';
- path_tmpdir_buffer[0].size = pathLength-1;
- # else
- const char * t = getenv("TMPDIR");
- if (!t)
- {
- t = "/tmp";
- }
- string_new(path_tmpdir_buffer);
- string_append(path_tmpdir_buffer,t);
- # endif
- path_tmpdir_result = path_tmpdir_buffer[0].value;
- }
- return path_tmpdir_result;
-}
-
-OBJECT * path_tmpnam(void)
-{
- char name_buffer[64];
- # ifdef OS_NT
- unsigned long c0 = GetCurrentProcessId();
- # else
- unsigned long c0 = getpid();
- # endif
- static unsigned long c1 = 0;
- if (0 == c1) c1 = time(0)&0xffff;
- c1 += 1;
- sprintf(name_buffer,"jam%lx%lx.000",c0,c1);
- return object_new(name_buffer);
-}
+/*
+ * path_done()
+ */
 
-OBJECT * path_tmpfile(void)
+void path_done( void )
 {
- OBJECT * result = 0;
- OBJECT * tmpnam;
-
- string file_path;
- string_copy(&file_path,path_tmpdir());
- string_push_back(&file_path,PATH_DELIM);
- tmpnam = path_tmpnam();
- string_append(&file_path,object_str(tmpnam));
- object_free(tmpnam);
- result = object_new(file_path.value);
- string_free(&file_path);
-
- return result;
 }
-
-
-# endif /* unix, NT, OS/2, AmigaOS */

Deleted: branches/release/tools/build/v2/engine/pwd.c
==============================================================================
--- branches/release/tools/build/v2/engine/pwd.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
+++ (empty file)
@@ -1,76 +0,0 @@
-/* Copyright Vladimir Prus 2002, Rene Rivera 2005. 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) */
-
-#include "jam.h"
-#include "lists.h"
-#include "object.h"
-#include "pathsys.h"
-#include "mem.h"
-
-#include <limits.h>
-#include <errno.h>
-
-/* MinGW on windows declares PATH_MAX in limits.h */
-#if defined(NT) && ! defined(__GNUC__)
-#include <direct.h>
-#define PATH_MAX _MAX_PATH
-#else
-#include <unistd.h>
-#if defined(__COMO__)
- #include <linux/limits.h>
-#endif
-#endif
-
-#ifndef PATH_MAX
- #define PATH_MAX 1024
-#endif
-
-/* The current directory can't change in bjam, so optimize this to cache
-** the result.
-*/
-static OBJECT * pwd_result = NULL;
-
-
-LIST*
-pwd(void)
-{
- if (!pwd_result)
- {
- int buffer_size = PATH_MAX;
- char * result_buffer = 0;
- do
- {
- char * buffer = BJAM_MALLOC_RAW(buffer_size);
- result_buffer = getcwd(buffer,buffer_size);
- if (result_buffer)
- {
- #ifdef NT
- OBJECT * result = object_new(result_buffer);
- pwd_result = short_path_to_long_path(result);
- object_free( result );
- #else
- pwd_result = object_new(result_buffer);
- #endif
- }
- buffer_size *= 2;
- BJAM_FREE_RAW(buffer);
- }
- while (!pwd_result && errno == ERANGE);
-
- if (!pwd_result)
- {
- perror("can not get current directory");
- return L0;
- }
- }
- return list_new( object_copy( pwd_result ) );
-}
-
-void pwd_done( void )
-{
- if( pwd_result )
- {
- object_free( pwd_result );
- }
-}

Deleted: branches/release/tools/build/v2/engine/pwd.h
==============================================================================
--- branches/release/tools/build/v2/engine/pwd.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
+++ (empty file)
@@ -1,11 +0,0 @@
-/* Copyright Vladimir Prus 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) */
-
-#ifndef PWD_H
-#define PWD_H
-
-LIST * pwd( void );
-void pwd_done( void );
-
-#endif

Modified: branches/release/tools/build/v2/engine/regexp.c
==============================================================================
--- branches/release/tools/build/v2/engine/regexp.c (original)
+++ branches/release/tools/build/v2/engine/regexp.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -45,10 +45,11 @@
 
 #include "jam.h"
 #include "regexp.h"
+
 #include <stdio.h>
 #include <ctype.h>
 #ifndef ultrix
- #include <stdlib.h>
+# include <stdlib.h>
 #endif
 #include <string.h>
 

Modified: branches/release/tools/build/v2/engine/regexp.h
==============================================================================
--- branches/release/tools/build/v2/engine/regexp.h (original)
+++ branches/release/tools/build/v2/engine/regexp.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,28 +5,30 @@
  * not the System V one.
  */
 #ifndef REGEXP_DWA20011023_H
-# define REGEXP_DWA20011023_H
+#define REGEXP_DWA20011023_H
 
 #define NSUBEXP 10
 typedef struct regexp {
- const char *startp[NSUBEXP];
- const char *endp[NSUBEXP];
+ char const * startp[ NSUBEXP ];
+ char const * endp[ NSUBEXP ];
     char regstart; /* Internal use only. */
     char reganch; /* Internal use only. */
- char *regmust; /* Internal use only. */
+ char * regmust; /* Internal use only. */
     int regmlen; /* Internal use only. */
- char program[1]; /* Unwarranted chumminess with compiler. */
+ char program[ 1 ]; /* Unwarranted chumminess with compiler. */
 } regexp;
 
-regexp *regcomp( const char *exp );
-int regexec( regexp *prog, const char *string );
-void regerror( const char *s );
+
+regexp * regcomp( char const * exp );
+int regexec( regexp * prog, char const * string );
+void regerror( char const * s );
+
 
 /*
  * The first byte of the regexp internal "program" is actually this magic
  * number; the start node begins in the second byte.
  */
-#define MAGIC 0234
+#define MAGIC 0234
 
 #endif
 

Modified: branches/release/tools/build/v2/engine/rules.c
==============================================================================
--- branches/release/tools/build/v2/engine/rules.c (original)
+++ branches/release/tools/build/v2/engine/rules.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,19 +4,6 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-# include "jam.h"
-# include "lists.h"
-# include "parse.h"
-# include "variable.h"
-# include "rules.h"
-# include "object.h"
-# include "hash.h"
-# include "modules.h"
-# include "search.h"
-# include "lists.h"
-# include "pathsys.h"
-# include "timestamp.h"
-
 /* This file is ALSO:
  * Copyright 2001-2004 David Abrahams.
  * Distributed under the Boost Software License, Version 1.0.
@@ -27,7 +14,6 @@
  * rules.c - access to RULEs, TARGETs, and ACTIONs
  *
  * External routines:
- *
  * bindrule() - return pointer to RULE, creating it if necessary.
  * bindtarget() - return pointer to TARGET, creating it if necessary.
  * touch_target() - mark a target to simulate being new.
@@ -39,35 +25,72 @@
  * popsettings() - reset target specific variables to their pre-push values.
  * freesettings() - delete a settings list.
  * rules_done() - free RULE and TARGET tables.
- *
- * 04/12/94 (seiwald) - actionlist() now just appends a single action.
- * 08/23/94 (seiwald) - Support for '+=' (append to variable)
  */
 
+#include "jam.h"
+#include "rules.h"
+
+#include "hash.h"
+#include "lists.h"
+#include "object.h"
+#include "parse.h"
+#include "pathsys.h"
+#include "search.h"
+#include "variable.h"
+
+
 static void set_rule_actions( RULE *, rule_actions * );
-static void set_rule_body ( RULE *, FUNCTION * procedure );
+static void set_rule_body ( RULE *, FUNCTION * );
 
 static struct hash * targethash = 0;
 
 
 /*
- * target_include() - adds the 'included' TARGET to the list of targets included
- * by the 'including' TARGET. Such targets are modeled as dependencies of the
- * internal include node belonging to the 'including' TARGET.
+ * get_target_includes() - lazy creates a target's internal includes node
+ *
+ * The newly created node is not entered into the hash table as there should
+ * never be a need to bind them directly from a target names. If you want to
+ * access an internal includes node by name, first access the actual target and
+ * then read the internal includes node from there.
  */
 
-void target_include( TARGET * including, TARGET * included )
+static TARGET * get_target_includes( TARGET * const t )
 {
- TARGET * internal;
- if ( !including->includes )
+ if ( !t->includes )
     {
- including->includes = copytarget( including );
- including->includes->original_target = including;
+ TARGET * const i = (TARGET *)BJAM_MALLOC( sizeof( *t ) );
+ memset( (char *)i, '\0', sizeof( *i ) );
+ i->name = object_copy( t->name );
+ i->boundname = object_copy( i->name );
+ i->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
+ i->original_target = t;
+ t->includes = i;
     }
- internal = including->includes;
+ return t->includes;
+}
+
+
+/*
+ * target_include() - adds a target to the given targe's 'included' list
+ * target_include_many() - adds targets to the given target's 'included' list
+ *
+ * Included targets are modeled as dependencies of the including target's
+ * internal include node.
+ */
+
+void target_include( TARGET * const including, TARGET * const included )
+{
+ TARGET * const internal = get_target_includes( including );
     internal->depends = targetentry( internal->depends, included );
 }
 
+void target_include_many( TARGET * const including, LIST * const included_names
+ )
+{
+ TARGET * const internal = get_target_includes( including );
+ internal->depends = targetlist( internal->depends, included_names );
+}
+
 
 /*
  * enter_rule() - return pointer to RULE, creating it if necessary in
@@ -77,9 +100,8 @@
 static RULE * enter_rule( OBJECT * rulename, module_t * target_module )
 {
     int found;
- RULE * r;
-
- r = (RULE *)hash_insert( demand_rules(target_module), rulename, &found );
+ RULE * const r = (RULE *)hash_insert( demand_rules( target_module ),
+ rulename, &found );
     if ( !found )
     {
         r->name = object_copy( rulename );
@@ -99,19 +121,17 @@
  * src_module.
  */
 
-static RULE * define_rule
-(
- module_t * src_module,
- OBJECT * rulename,
- module_t * target_module
-)
+static RULE * define_rule( module_t * src_module, OBJECT * rulename,
+ module_t * target_module )
 {
- RULE * r = enter_rule( rulename, target_module );
- if ( r->module != src_module ) /* if the rule was imported from elsewhere, clear it now */
+ RULE * const r = enter_rule( rulename, target_module );
+ if ( r->module != src_module )
     {
+ /* If the rule was imported from elsewhere, clear it now. */
         set_rule_body( r, 0 );
         set_rule_actions( r, 0 );
- r->module = src_module; /* r will be executed in the source module */
+ /* r will be executed in the source module. */
+ r->module = src_module;
     }
     return r;
 }
@@ -134,7 +154,7 @@
  * bindtarget() - return pointer to TARGET, creating it if necessary.
  */
 
-TARGET * bindtarget( OBJECT * target_name )
+TARGET * bindtarget( OBJECT * const target_name )
 {
     int found;
     TARGET * t;
@@ -159,19 +179,13 @@
     TARGET * t = (TARGET *)xtarget;
     if ( !( t->flags & T_FLAG_NOTFILE ) )
     {
- /* Check if there's a setting for LOCATE */
+ /* Check if there is a setting for LOCATE. */
         SETTINGS * s = t->settings;
         for ( ; s ; s = s->next )
         {
- if ( strcmp( object_str( s->symbol ), "LOCATE" ) == 0 )
+ if ( object_equal( s->symbol, constant_LOCATE ) && ! list_empty( s->value ) )
             {
- pushsettings( root_module(), t->settings );
- /* We are binding a target with explicit LOCATE. So third
- * argument is of no use: nothing will be returned through it.
- */
- object_free( t->boundname );
- t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( root_module(), t->settings );
+ set_explicit_binding( t->name, list_front( s->value ) );
                 break;
             }
         }
@@ -187,31 +201,32 @@
 
 
 /*
- * copytarget() - make a new target with the old target's name.
- *
- * Not entered into hash table -- for internal nodes.
+ * touch_target() - mark a target to simulate being new.
  */
 
-TARGET * copytarget( const TARGET * ot )
+void touch_target( OBJECT * const t )
 {
- TARGET * t = (TARGET *)BJAM_MALLOC( sizeof( *t ) );
- memset( (char *)t, '\0', sizeof( *t ) );
- t->name = object_copy( ot->name );
- t->boundname = object_copy( t->name );
-
- t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
-
- return t;
+ bindtarget( t )->flags |= T_FLAG_TOUCHED;
 }
 
 
 /*
- * touch_target() - mark a target to simulate being new.
+ * target_scc() - returns the root of a strongly connected component that this
+ * target is a part of.
  */
 
-void touch_target( OBJECT * t )
+TARGET * target_scc( TARGET * t )
 {
- bindtarget( t )->flags |= T_FLAG_TOUCHED;
+ TARGET * result = t;
+ while ( result->scc_root )
+ result = result->scc_root;
+ while ( t->scc_root )
+ {
+ TARGET * const tmp = t->scc_root;
+ t->scc_root = result;
+ t = tmp;
+ }
+ return result;
 }
 
 
@@ -219,13 +234,14 @@
  * targetlist() - turn list of target names into a TARGET chain.
  *
  * Inputs:
- * chain existing TARGETS to append to
- * targets list of target names
+ * chain existing TARGETS to append to
+ * targets list of target names
  */
 
 TARGETS * targetlist( TARGETS * chain, LIST * target_names )
 {
- LISTITER iter = list_begin( target_names ), end = list_end( target_names );
+ LISTITER iter = list_begin( target_names );
+ LISTITER const end = list_end( target_names );
     for ( ; iter != end; iter = list_next( iter ) )
         chain = targetentry( chain, bindtarget( list_item( iter ) ) );
     return chain;
@@ -242,7 +258,7 @@
 
 TARGETS * targetentry( TARGETS * chain, TARGET * target )
 {
- TARGETS * c = (TARGETS *)BJAM_MALLOC( sizeof( TARGETS ) );
+ TARGETS * const c = (TARGETS *)BJAM_MALLOC( sizeof( TARGETS ) );
     c->target = target;
 
     if ( !chain ) chain = c;
@@ -258,27 +274,25 @@
  * targetchain() - append two TARGET chains.
  *
  * Inputs:
- * chain exisitng TARGETS to append to
+ * chain existing TARGETS to append to
  * target new target to append
  */
 
 TARGETS * targetchain( TARGETS * chain, TARGETS * targets )
 {
     if ( !targets ) return chain;
- if ( !chain ) return targets;
+ if ( !chain ) return targets;
 
     chain->tail->next = targets;
     chain->tail = targets->tail;
-
     return chain;
 }
 
 /*
- * action_free - decrement the ACTIONs refrence count
- * and (maybe) free it.
+ * action_free - decrement the ACTIONs refrence count and (maybe) free it.
  */
 
-void action_free ( ACTION * action )
+void action_free( ACTION * action )
 {
     if ( --action->refs == 0 )
     {
@@ -288,22 +302,20 @@
     }
 }
 
+
 /*
  * actionlist() - append to an ACTION chain.
  */
 
 ACTIONS * actionlist( ACTIONS * chain, ACTION * action )
 {
- ACTIONS * actions = (ACTIONS *)BJAM_MALLOC( sizeof( ACTIONS ) );
-
+ ACTIONS * const actions = (ACTIONS *)BJAM_MALLOC( sizeof( ACTIONS ) );
     actions->action = action;
-
     ++action->refs;
     if ( !chain ) chain = actions;
     else chain->tail->next = actions;
     chain->tail = actions;
     actions->next = 0;
-
     return chain;
 }
 
@@ -315,11 +327,12 @@
  *
  * Adds a variable setting (varname=list) onto a chain of settings for a
  * particular target. 'flag' controls the relationship between new and old
- * values in the same way as in var_set() function (see variable.c). Returns
- * the head of the settings chain.
+ * values in the same way as in var_set() function (see variable.c). Returns the
+ * head of the settings chain.
  */
 
-SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol, LIST * value )
+SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol,
+ LIST * value )
 {
     SETTINGS * v;
 
@@ -334,7 +347,6 @@
     if ( !v )
     {
         v = settings_freelist;
-
         if ( v )
             settings_freelist = v->next;
         else
@@ -405,7 +417,7 @@
 {
     while ( chain )
     {
- TARGETS * n = chain->next;
+ TARGETS * const n = chain->next;
         BJAM_FREE( chain );
         chain = n;
     }
@@ -420,7 +432,7 @@
 {
     while ( chain )
     {
- ACTIONS * n = chain->next;
+ ACTIONS * const n = chain->next;
         action_free( chain->action );
         BJAM_FREE( chain );
         chain = n;
@@ -436,7 +448,7 @@
 {
     while ( v )
     {
- SETTINGS * n = v->next;
+ SETTINGS * const n = v->next;
         object_free( v->symbol );
         list_free( v->value );
         v->next = settings_freelist;
@@ -448,7 +460,7 @@
 
 static void freetarget( void * xt, void * data )
 {
- TARGET * t = (TARGET *)xt;
+ TARGET * const t = (TARGET *)xt;
     if ( t->name ) object_free ( t->name );
     if ( t->boundname ) object_free ( t->boundname );
     if ( t->settings ) freesettings( t->settings );
@@ -456,7 +468,6 @@
     if ( t->dependants ) freetargets ( t->dependants );
     if ( t->parents ) freetargets ( t->parents );
     if ( t->actions ) freeactions ( t->actions );
-
     if ( t->includes )
     {
         freetarget( t->includes, (void *)0 );
@@ -478,7 +489,7 @@
     }
     while ( settings_freelist )
     {
- SETTINGS * n = settings_freelist->next;
+ SETTINGS * const n = settings_freelist->next;
         BJAM_FREE( settings_freelist );
         settings_freelist = n;
     }
@@ -496,7 +507,7 @@
 
 
 /*
- * actions_free() - release a reference to the given actions.
+ * actions_free() - release a reference to given actions.
  */
 
 void actions_free( rule_actions * a )
@@ -509,6 +520,7 @@
     }
 }
 
+
 /*
  * set_rule_body() - set the argument list and procedure of the given rule.
  */
@@ -534,7 +546,7 @@
         return object_copy( r->name );
 
     {
- char name[4096] = "";
+ char name[ 4096 ] = "";
         if ( r->module->name )
         {
             strncat( name, object_str( r->module->name ), sizeof( name ) - 1 );
@@ -547,7 +559,7 @@
 
 
 /*
- * global_rule() - given a rule, produce the corresponding entry in the global
+ * global_rule() - given a rule, produce a corresponding entry in the global
  * module.
  */
 
@@ -557,8 +569,8 @@
         return r;
 
     {
- OBJECT * name = global_rule_name( r );
- RULE * result = define_rule( r->module, name, root_module() );
+ OBJECT * const name = global_rule_name( r );
+ RULE * const result = define_rule( r->module, name, root_module() );
         object_free( name );
         return result;
     }
@@ -571,9 +583,10 @@
  * exported to the global module as modulename.rulename.
  */
 
-RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure, int exported )
+RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure,
+ int exported )
 {
- RULE * local = define_rule( m, rulename, m );
+ RULE * const local = define_rule( m, rulename, m );
     local->exported = exported;
     set_rule_body( local, procedure );
 
@@ -582,7 +595,7 @@
      * can use, e.g. in profiling output. Only do this once, since this could be
      * called multiple times with the same procedure.
      */
- if ( function_rulename( procedure ) == 0 )
+ if ( !function_rulename( procedure ) )
         function_set_rulename( procedure, global_rule_name( local ) );
 
     return local;
@@ -599,9 +612,11 @@
 }
 
 
-static rule_actions * actions_new( FUNCTION * command, LIST * bindlist, int flags )
+static rule_actions * actions_new( FUNCTION * command, LIST * bindlist,
+ int flags )
 {
- rule_actions * result = (rule_actions *)BJAM_MALLOC( sizeof( rule_actions ) );
+ rule_actions * const result = (rule_actions *)BJAM_MALLOC( sizeof(
+ rule_actions ) );
     function_refer( command );
     result->command = command;
     result->bindlist = bindlist;
@@ -611,10 +626,11 @@
 }
 
 
-RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags )
+RULE * new_rule_actions( module_t * m, OBJECT * rulename, FUNCTION * command,
+ LIST * bindlist, int flags )
 {
- RULE * local = define_rule( m, rulename, m );
- RULE * global = global_rule( local );
+ RULE * const local = define_rule( m, rulename, m );
+ RULE * const global = global_rule( local );
     set_rule_actions( local, actions_new( command, bindlist, flags ) );
     set_rule_actions( global, local->actions );
     return local;
@@ -623,8 +639,8 @@
 
 /*
  * Looks for a rule in the specified module, and returns it, if found. First
- * checks if the rule is present in the module's rule table. Second, if name of
- * the rule is in the form name1.name2 and name1 is in the list of imported
+ * checks if the rule is present in the module's rule table. Second, if the
+ * rule's name is in the form name1.name2 and name1 is in the list of imported
  * modules, look in module 'name1' for rule 'name2'.
  */
 
@@ -642,23 +658,25 @@
     else if ( !local_only && m->imported_modules )
     {
         /* Try splitting the name into module and rule. */
- char *p = strchr( object_str( rulename ), '.' ) ;
+ char * p = strchr( object_str( rulename ), '.' ) ;
         if ( p )
         {
- string buf[1];
- OBJECT * module_part;
- OBJECT * rule_part;
- string_new( buf );
- string_append_range( buf, object_str( rulename ), p );
- module_part = object_new( buf->value );
- rule_part = object_new( p + 1 );
- /* Now, r->name keeps the module name, and p+1 keeps the rule name.
+ /* Now, r->name keeps the module name, and p + 1 keeps the rule
+ * name.
              */
+ OBJECT * rule_part = object_new( p + 1 );
+ OBJECT * module_part;
+ {
+ string buf[ 1 ];
+ string_new( buf );
+ string_append_range( buf, object_str( rulename ), p );
+ module_part = object_new( buf->value );
+ string_free( buf );
+ }
             if ( hash_find( m->imported_modules, module_part ) )
                 result = lookup_rule( rule_part, bindmodule( module_part ), 1 );
- object_free( rule_part );
             object_free( module_part );
- string_free( buf );
+ object_free( rule_part );
         }
     }
 
@@ -666,18 +684,17 @@
     {
         if ( local_only && !result->exported )
             result = 0;
- else
+ else if ( original_module != m )
         {
             /* Lookup started in class module. We have found a rule in class
              * module, which is marked for execution in that module, or in some
- * instances. Mark it for execution in the instance where we started
+ * instance. Mark it for execution in the instance where we started
              * the lookup.
              */
- int execute_in_class = ( result->module == m );
- int execute_in_some_instance = ( result->module->class_module &&
- ( result->module->class_module == m ) );
- if ( ( original_module != m ) &&
- ( execute_in_class || execute_in_some_instance ) )
+ int const execute_in_class = result->module == m;
+ int const execute_in_some_instance =
+ result->module->class_module == m;
+ if ( execute_in_class || execute_in_some_instance )
                 result->module = original_module;
         }
     }
@@ -703,7 +720,7 @@
 
 RULE * import_rule( RULE * source, module_t * m, OBJECT * name )
 {
- RULE * dest = define_rule( source->module, name, m );
+ RULE * const dest = define_rule( source->module, name, m );
     set_rule_body( dest, source->procedure );
     set_rule_actions( dest, source->actions );
     return dest;
@@ -721,4 +738,3 @@
         rule->procedure = procedure;
     }
 }
-

Modified: branches/release/tools/build/v2/engine/rules.h
==============================================================================
--- branches/release/tools/build/v2/engine/rules.h (original)
+++ branches/release/tools/build/v2/engine/rules.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,20 +10,11 @@
  * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  */
 
-#ifndef RULES_DWA_20011020_H
-#define RULES_DWA_20011020_H
-
-#include "modules.h"
-#include "jam.h"
-#include "function.h"
-
-
 /*
  * rules.h - targets, rules, and related information
  *
- * This file describes the structures holding the targets, rules, and
- * related information accumulated by interpreting the statements
- * of the jam files.
+ * This file describes the structures holding the targets, rules, and related
+ * information accumulated by interpreting the statements of the jam files.
  *
  * The following are defined:
  *
@@ -33,16 +24,16 @@
  * SETTINGS - variables to set when executing a TARGET's ACTIONS.
  * TARGETS - a chain of TARGETs.
  * TARGET - an entity (e.g. a file) that can be built.
- *
- * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET.
- * 04/12/94 (seiwald) - actionlist() now just appends a single action.
- * 06/01/94 (seiwald) - new 'actions existing' does existing sources
- * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
- * 01/19/95 (seiwald) - split DONTKNOW into CANTFIND/CANTMAKE.
- * 02/02/95 (seiwald) - new LEAVES modifier on targets.
- * 02/14/95 (seiwald) - new NOUPDATE modifier on targets.
  */
 
+#ifndef RULES_DWA_20011020_H
+#define RULES_DWA_20011020_H
+
+#include "function.h"
+#include "modules.h"
+#include "timestamp.h"
+
+
 typedef struct _rule RULE;
 typedef struct _target TARGET;
 typedef struct _targets TARGETS;
@@ -146,19 +137,18 @@
 
 /* This flag was added to support a new built-in rule named "FAIL_EXPECTED" used
  * to indicate that the result of running a given action should be inverted,
- * i.e. ok <=> fail. This is useful for launching certain test runs from a
- * Jamfile.
+ * i.e. ok <=> fail. Useful for launching certain test runs from a Jamfile.
  */
 #define T_FLAG_FAIL_EXPECTED 0x0100 /* FAIL_EXPECTED applied */
 
 #define T_FLAG_INTERNAL 0x0200 /* internal INCLUDES node */
 
-/* Indicates that the target must be a file. This prevents matching non-files,
- * like directories, when a target is searched.
+/* Indicates that the target must be a file. Prevents matching non-files, like
+ * directories, when a target is searched.
  */
 #define T_FLAG_ISFILE 0x0400
 
-#define T_FLAG_PRECIOUS 0x0800
+#define T_FLAG_PRECIOUS 0x0800
 
     char binding; /* how target relates to a real file or
                                        * folder
@@ -178,8 +168,8 @@
     TARGET * original_target; /* original_target->includes = this */
     char rescanned;
 
- time_t time; /* update time */
- time_t leaf; /* update time of leaf sources */
+ timestamp time; /* update time */
+ timestamp leaf; /* update time of leaf sources */
 
     char fate; /* make0()'s diagnosis */
 
@@ -188,13 +178,13 @@
 
 #define T_FATE_STABLE 2 /* target did not need updating */
 #define T_FATE_NEWER 3 /* target newer than parent */
-
+
 #define T_FATE_SPOIL 4 /* >= SPOIL rebuilds parents */
 #define T_FATE_ISTMP 4 /* unneeded temp target oddly present */
 
 #define T_FATE_BUILD 5 /* >= BUILD rebuilds target */
 #define T_FATE_TOUCHED 5 /* manually touched with -t */
-#define T_FATE_REBUILD 6
+#define T_FATE_REBUILD 6
 #define T_FATE_MISSING 7 /* is missing, needs updating */
 #define T_FATE_NEEDTMP 8 /* missing temp that must be rebuild */
 #define T_FATE_OUTDATED 9 /* is out of date, needs updating */
@@ -225,9 +215,17 @@
 
     int asynccnt; /* child deps outstanding */
     TARGETS * parents; /* used by make1() for completion */
+ TARGET * scc_root; /* used by make to resolve cyclic includes
+ */
+ TARGET * rescanning; /* used by make0 to mark visited targets
+ * when rescanning
+ */
+ int depth; /* The depth of the target in the make0
+ * stack.
+ */
     char * cmds; /* type-punned command list */
 
- const char * failed;
+ char const * failed;
 };
 
 
@@ -236,8 +234,8 @@
 ACTIONS * actionlist ( ACTIONS *, ACTION * );
 void freeactions ( ACTIONS * );
 SETTINGS * addsettings ( SETTINGS *, int flag, OBJECT * symbol, LIST * value );
-void pushsettings ( struct module_t * module, SETTINGS * );
-void popsettings ( struct module_t * module, SETTINGS * );
+void pushsettings ( module_t *, SETTINGS * );
+void popsettings ( module_t *, SETTINGS * );
 SETTINGS * copysettings ( SETTINGS * );
 void freesettings ( SETTINGS * );
 void actions_refer( rule_actions * );
@@ -253,15 +251,18 @@
 
 /* Target related functions. */
 void bind_explicitly_located_targets();
-TARGET * bindtarget ( OBJECT * target_name );
-TARGET * copytarget ( TARGET const * t );
+TARGET * bindtarget ( OBJECT * const );
 void freetargets ( TARGETS * );
-TARGETS * targetchain ( TARGETS * chain, TARGETS * );
-TARGETS * targetentry ( TARGETS * chain, TARGET * );
-void target_include ( TARGET * including, TARGET * included );
-TARGETS * targetlist ( TARGETS * chain, LIST * target_names );
-void touch_target ( OBJECT * t );
+TARGETS * targetchain ( TARGETS *, TARGETS * );
+TARGETS * targetentry ( TARGETS *, TARGET * );
+void target_include ( TARGET * const including,
+ TARGET * const included );
+void target_include_many ( TARGET * const including,
+ LIST * const included_names );
+TARGETS * targetlist ( TARGETS *, LIST * target_names );
+void touch_target ( OBJECT * const );
 void clear_includes ( TARGET * );
+TARGET * target_scc ( TARGET * );
 
 /* Final module cleanup. */
 void rules_done();

Modified: branches/release/tools/build/v2/engine/scan.c
==============================================================================
--- branches/release/tools/build/v2/engine/scan.c (original)
+++ branches/release/tools/build/v2/engine/scan.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,28 +4,19 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-#include "jam.h"
-#include "lists.h"
-#include "parse.h"
-#include "scan.h"
-#include "jamgram.h"
-#include "jambase.h"
-#include "object.h"
-#include "constants.h"
-
 /*
  * scan.c - the jam yacc scanner
  *
- * 12/26/93 (seiwald) - bump buf in yylex to 10240 - yuk.
- * 09/16/94 (seiwald) - check for overflows, unmatched {}'s, etc.
- * Also handle tokens abutting EOF by remembering
- * to return EOF now matter how many times yylex()
- * reinvokes yyline().
- * 02/11/95 (seiwald) - honor only punctuation keywords if SCAN_PUNCT.
- * 07/27/95 (seiwald) - Include jamgram.h after scan.h, so that YYSTYPE is
- * defined before Linux's yacc tries to redefine it.
  */
 
+#include "jam.h"
+#include "scan.h"
+
+#include "constants.h"
+#include "jambase.h"
+#include "jamgram.h"
+
+
 struct keyword
 {
     char * word;
@@ -36,18 +27,19 @@
     { 0, 0 }
 };
 
+typedef struct include include;
 struct include
 {
- struct include * next; /* next serial include file */
- char * string; /* pointer into current line */
- char * * strings; /* for yyfparse() -- text to parse */
- FILE * file; /* for yyfparse() -- file being read */
- OBJECT * fname; /* for yyfparse() -- file name */
- int line; /* line counter for error messages */
- char buf[ 512 ]; /* for yyfparse() -- line buffer */
+ include * next; /* next serial include file */
+ char * string; /* pointer into current line */
+ char * * strings; /* for yyfparse() -- text to parse */
+ FILE * file; /* for yyfparse() -- file being read */
+ OBJECT * fname; /* for yyfparse() -- file name */
+ int line; /* line counter for error messages */
+ char buf[ 512 ]; /* for yyfparse() -- line buffer */
 };
 
-static struct include * incp = 0; /* current file; head of chain */
+static include * incp = 0; /* current file; head of chain */
 
 static int scanmode = SCAN_NORMAL;
 static int anyerrors = 0;
@@ -68,22 +60,20 @@
 }
 
 
-void yyerror( const char * s )
+void yyerror( char const * s )
 {
     /* We use yylval instead of incp to access the error location information as
      * the incp pointer will already be reset to 0 in case the error occurred at
      * EOF.
      *
- * The two may differ only if we get an error while reading a lexical token
- * spanning muliple lines, e.g. a multi-line string literal or action body,
- * in which case yylval location information will hold the information about
- * where this token started while incp will hold the information about where
- * reading it broke.
- *
- * TODO: Test the theory about when yylval and incp location information are
- * the same and when they differ.
+ * The two may differ only if ran into an unexpected EOF or we get an error
+ * while reading a lexical token spanning multiple lines, e.g. a multi-line
+ * string literal or action body, in which case yylval location information
+ * will hold the information about where the token started while incp will
+ * hold the information about where reading it broke.
      */
- printf( "%s:%d: %s at %s\n", object_str( yylval.file ), yylval.line, s, symdump( &yylval ) );
+ printf( "%s:%d: %s at %s\n", object_str( yylval.file ), yylval.line, s,
+ symdump( &yylval ) );
     ++anyerrors;
 }
 
@@ -96,7 +86,7 @@
 
 void yyfparse( OBJECT * s )
 {
- struct include * i = (struct include *)BJAM_MALLOC( sizeof( *i ) );
+ include * i = (include *)BJAM_MALLOC( sizeof( *i ) );
 
     /* Push this onto the incp chain. */
     i->string = "";
@@ -122,7 +112,7 @@
 
 int yyline()
 {
- struct include * i = incp;
+ include * const i = incp;
 
     if ( !incp )
         return EOF;
@@ -265,7 +255,7 @@
         int notkeyword;
 
         /* Eat white space. */
- for ( ;; )
+ for ( ; ; )
         {
             /* Skip past white space. */
             while ( ( c != EOF ) && isspace( c ) )
@@ -389,11 +379,11 @@
     static char buf[ BIGGEST_TOKEN + 20 ];
     switch ( s->type )
     {
- case EOF : sprintf( buf, "EOF" ); break;
+ case EOF : sprintf( buf, "EOF" ); break;
         case 0 : sprintf( buf, "unknown symbol %s", object_str( s->string ) ); break;
         case ARG : sprintf( buf, "argument %s" , object_str( s->string ) ); break;
         case STRING: sprintf( buf, "string \"%s\"" , object_str( s->string ) ); break;
- default : sprintf( buf, "keyword %s" , s->keyword ); break;
+ default : sprintf( buf, "keyword %s" , s->keyword ); break;
     }
     return buf;
 }
@@ -404,16 +394,11 @@
  * transitions that produce a parse.
  */
 
-void yyinput_stream( OBJECT * * name, int * line )
+void yyinput_last_read_token( OBJECT * * name, int * line )
 {
- if ( incp )
- {
- *name = incp->fname;
- *line = incp->line;
- }
- else
- {
- *name = constant_builtin;
- *line = -1;
- }
+ /* TODO: Consider whether and when we might want to report where the last
+ * read token ended, e.g. EOF errors inside string literals.
+ */
+ *name = yylval.file;
+ *line = yylval.line;
 }

Modified: branches/release/tools/build/v2/engine/scan.h
==============================================================================
--- branches/release/tools/build/v2/engine/scan.h (original)
+++ branches/release/tools/build/v2/engine/scan.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,6 @@
  * scan.h - the jam yacc scanner
  *
  * External functions:
- *
  * yyerror( char *s ) - print a parsing error message.
  * yyfparse( char *s ) - scan include file s.
  * yylex() - parse the next token, returning its type.
@@ -23,6 +22,11 @@
  * lists without quoting.
  */
 
+#include "lists.h"
+#include "object.h"
+#include "parse.h"
+
+
 /*
  * YYSTYPE - value of a lexical token
  */
@@ -38,20 +42,20 @@
     int number;
     OBJECT * file;
     int line;
- const char * keyword;
+ char const * keyword;
 } YYSTYPE;
 
 extern YYSTYPE yylval;
 
 void yymode( int n );
-void yyerror( const char * s );
+void yyerror( char const * s );
 int yyanyerrors();
 void yyfparse( OBJECT * s );
 int yyline();
 int yylex();
 int yyparse();
-void yyinput_stream( OBJECT * * name, int * line );
+void yyinput_last_read_token( OBJECT * * name, int * line );
 
-# define SCAN_NORMAL 0 /* normal parsing */
-# define SCAN_STRING 1 /* look only for matching } */
-# define SCAN_PUNCT 2 /* only punctuation keywords */
+#define SCAN_NORMAL 0 /* normal parsing */
+#define SCAN_STRING 1 /* look only for matching } */
+#define SCAN_PUNCT 2 /* only punctuation keywords */

Modified: branches/release/tools/build/v2/engine/search.c
==============================================================================
--- branches/release/tools/build/v2/engine/search.c (original)
+++ branches/release/tools/build/v2/engine/search.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,23 +4,26 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * 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)
  */
 
 #include "jam.h"
-#include "lists.h"
 #include "search.h"
-#include "timestamp.h"
-#include "pathsys.h"
-#include "variable.h"
-#include "object.h"
+
 #include "compile.h"
-#include "strings.h"
-#include "hash.h"
 #include "filesys.h"
+#include "hash.h"
+#include "lists.h"
+#include "object.h"
+#include "pathsys.h"
+#include "strings.h"
+#include "timestamp.h"
+#include "variable.h"
+
 #include <string.h>
 
 
@@ -30,16 +33,12 @@
     OBJECT * target;
 } BINDING;
 
-static struct hash *explicit_bindings = 0;
+static struct hash * explicit_bindings = 0;
 
 
-void call_bind_rule
-(
- OBJECT * target_,
- OBJECT * boundname_
-)
+void call_bind_rule( OBJECT * target_, OBJECT * boundname_ )
 {
- LIST * bind_rule = var_get( root_module(), constant_BINDRULE );
+ LIST * const bind_rule = var_get( root_module(), constant_BINDRULE );
     if ( !list_empty( bind_rule ) )
     {
         OBJECT * target = object_copy( target_ );
@@ -47,7 +46,7 @@
         if ( boundname && target )
         {
             /* Prepare the argument list. */
- FRAME frame[1];
+ FRAME frame[ 1 ];
             frame_init( frame );
 
             /* First argument is the target name. */
@@ -55,7 +54,10 @@
 
             lol_add( frame->args, list_new( boundname ) );
             if ( lol_get( frame->args, 1 ) )
- list_free( evaluate_rule( list_front( bind_rule ), frame ) );
+ {
+ OBJECT * rulename = list_front( bind_rule );
+ list_free( evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ) );
+ }
 
             /* Clean up */
             frame_free( frame );
@@ -70,48 +72,87 @@
     }
 }
 
+/* Records the binding of a target with an explicit LOCATE. */
+void set_explicit_binding( OBJECT * target, OBJECT * locate )
+{
+ OBJECT * boundname;
+ OBJECT * key;
+ PATHNAME f[ 1 ];
+ string buf[ 1 ];
+ int found;
+ BINDING * ba;
+
+ if ( !explicit_bindings )
+ explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
+ "locations" );
+
+ string_new( buf );
+
+ /* Parse the filename. */
+ path_parse( object_str( target ), f );
+
+ /* Ignore the grist. */
+ f->f_grist.ptr = 0;
+ f->f_grist.len = 0;
+
+ /* Root the target path at the given location. */
+ f->f_root.ptr = object_str( locate );
+ f->f_root.len = strlen( object_str( locate ) );
+
+ path_build( f, buf );
+ boundname = object_new( buf->value );
+ if ( DEBUG_SEARCH )
+ printf( "explicit locate %s: %s\n", object_str( target ), buf->value );
+ string_free( buf );
+ key = path_as_key( boundname );
+ object_free( boundname );
+
+ ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
+ if ( !found )
+ {
+ ba->binding = key;
+ ba->target = target;
+ }
+ else
+ object_free( key );
+}
+
 /*
- * search.c - find a target along $(SEARCH) or $(LOCATE)
- * First, check if LOCATE is set. If so, use it to determine
- * the location of target and return, regardless of whether anything
- * exists on that location.
+ * search.c - find a target along $(SEARCH) or $(LOCATE).
+ *
+ * First, check if LOCATE is set. If so, use it to determine the location of
+ * target and return, regardless of whether anything exists at that location.
+ *
+ * Second, examine all directories in SEARCH. If the file exists there or there
+ * is another target with the same name already placed at this location via the
+ * LOCATE setting, stop and return the location. In case of a previous target,
+ * return its name via the 'another_target' argument.
  *
- * Second, examine all directories in SEARCH. If there's file already
- * or there's another target with the same name which was placed
- * to this location via LOCATE setting, stop and return the location.
- * In case of previous target, return it's name via the third argument.
+ * This behaviour allows handling dependencies on generated files.
  *
- * This bevahiour allow to handle dependency on generated files. If
- * caller does not expect that target is generated, 0 can be passed as
- * the third argument.
+ * If caller does not expect that the target is generated, 0 can be passed as
+ * 'another_target'.
  */
 
-OBJECT *
-search(
- OBJECT * target,
- time_t *time,
- OBJECT * * another_target,
- int file
-)
-{
- PATHNAME f[1];
- LIST * varlist;
- string buf[1];
- int found = 0;
- /* Will be set to 1 if target location is specified via LOCATE. */
- int explicitly_located = 0;
+OBJECT * search( OBJECT * target, timestamp * const time,
+ OBJECT * * another_target, int const file )
+{
+ PATHNAME f[ 1 ];
+ LIST * varlist;
+ string buf[ 1 ];
+ int found = 0;
     OBJECT * boundname = 0;
 
     if ( another_target )
         *another_target = 0;
 
- if (! explicit_bindings )
- explicit_bindings = hashinit( sizeof(BINDING),
- "explicitly specified locations");
+ if ( !explicit_bindings )
+ explicit_bindings = hashinit( sizeof( BINDING ), "explicitly specified "
+ "locations" );
 
     string_new( buf );
- /* Parse the filename */
 
+ /* Parse the filename. */
     path_parse( object_str( target ), f );
 
     f->f_grist.ptr = 0;
@@ -124,25 +165,25 @@
         f->f_root.ptr = object_str( list_front( varlist ) );
         f->f_root.len = strlen( object_str( list_front( varlist ) ) );
 
- path_build( f, buf, 1 );
+ path_build( f, buf );
 
         if ( DEBUG_SEARCH )
             printf( "locate %s: %s\n", object_str( target ), buf->value );
 
- explicitly_located = 1;
-
         key = object_new( buf->value );
- timestamp( key, time );
+ timestamp_from_path( time, key );
         object_free( key );
         found = 1;
     }
- else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
+ else if ( varlist = var_get( root_module(), constant_SEARCH ),
+ !list_empty( varlist ) )
     {
- LISTITER iter = list_begin( varlist ), end = list_end( varlist );
+ LISTITER iter = list_begin( varlist );
+ LISTITER const end = list_end( varlist );
         for ( ; iter != end; iter = list_next( iter ) )
         {
             BINDING * ba;
- file_info_t *ff;
+ file_info_t * ff;
             OBJECT * key;
             OBJECT * test_path;
 
@@ -150,7 +191,7 @@
             f->f_root.len = strlen( object_str( list_item( iter ) ) );
 
             string_truncate( buf, 0 );
- path_build( f, buf, 1 );
+ path_build( f, buf );
 
             if ( DEBUG_SEARCH )
                 printf( "search %s: %s\n", object_str( target ), buf->value );
@@ -159,20 +200,20 @@
             key = path_as_key( test_path );
             object_free( test_path );
             ff = file_query( key );
- timestamp( key, time );
+ timestamp_from_path( time, key );
 
             if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
             {
                 if ( DEBUG_SEARCH )
                     printf(" search %s: found explicitly located target %s\n",
- object_str( target ), object_str( ba->target ) );
+ object_str( target ), object_str( ba->target ) );
                 if ( another_target )
                     *another_target = ba->target;
                 found = 1;
                 object_free( key );
                 break;
             }
- else if ( ff && ff->time )
+ else if ( ff )
             {
                 if ( !file || ff->is_file )
                 {
@@ -187,49 +228,30 @@
 
     if ( !found )
     {
- /* Look for the obvious */
- /* This is a questionable move. Should we look in the */
- /* obvious place if SEARCH is set? */
+ /* Look for the obvious. */
+ /* This is a questionable move. Should we look in the obvious place if
+ * SEARCH is set?
+ */
         OBJECT * key;
 
         f->f_root.ptr = 0;
         f->f_root.len = 0;
 
         string_truncate( buf, 0 );
- path_build( f, buf, 1 );
+ path_build( f, buf );
 
         if ( DEBUG_SEARCH )
             printf( "search %s: %s\n", object_str( target ), buf->value );
 
         key = object_new( buf->value );
- timestamp( key, time );
+ timestamp_from_path( time, key );
         object_free( key );
     }
 
     boundname = object_new( buf->value );
     string_free( buf );
 
- if ( explicitly_located )
- {
- int found;
- BINDING * ba;
- OBJECT * key = path_as_key( boundname );
- /* CONSIDER: we probably should issue a warning is another file
- is explicitly bound to the same location. This might break
- compatibility, though. */
- ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
- if ( !found )
- {
- ba->binding = key;
- ba->target = target;
- }
- else
- {
- object_free( key );
- }
- }
-
- /* prepare a call to BINDRULE if the variable is set */
+ /* Prepare a call to BINDRULE if the variable is set. */
     call_bind_rule( target, boundname );
 
     return boundname;
@@ -238,15 +260,15 @@
 
 static void free_binding( void * xbinding, void * data )
 {
- BINDING * binding = (BINDING *)xbinding;
- object_free( binding->binding );
+ object_free( ( (BINDING *)xbinding )->binding );
 }
 
+
 void search_done( void )
 {
     if ( explicit_bindings )
     {
- hashenumerate( explicit_bindings, free_binding, (void *)0 );
+ hashenumerate( explicit_bindings, free_binding, 0 );
         hashdone( explicit_bindings );
     }
 }

Modified: branches/release/tools/build/v2/engine/search.h
==============================================================================
--- branches/release/tools/build/v2/engine/search.h (original)
+++ branches/release/tools/build/v2/engine/search.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,9 +12,11 @@
 #define SEARCH_SW20111118_H
 
 #include "object.h"
-#include <time.h>
+#include "timestamp.h"
 
-OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target, int file );
+void set_explicit_binding( OBJECT * target, OBJECT * locate );
+OBJECT * search( OBJECT * target, timestamp * const time,
+ OBJECT * * another_target, int const file );
 void search_done( void );
 
 #endif

Modified: branches/release/tools/build/v2/engine/strings.c
==============================================================================
--- branches/release/tools/build/v2/engine/strings.c (original)
+++ branches/release/tools/build/v2/engine/strings.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,16 +4,16 @@
 
 #include "jam.h"
 #include "strings.h"
+
+#include <assert.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
-#include <stdio.h>
 
 
 #ifndef NDEBUG
 # define JAM_STRING_MAGIC ((char)0xcf)
 # define JAM_STRING_MAGIC_SIZE 4
-static void assert_invariants( string* self )
+static void assert_invariants( string * self )
 {
     int i;
 
@@ -21,18 +21,22 @@
     {
         assert( self->size == 0 );
         assert( self->capacity == 0 );
- assert( self->opt[0] == 0 );
+ assert( self->opt[ 0 ] == 0 );
         return;
     }
 
     assert( self->size < self->capacity );
- assert( ( self->capacity <= sizeof(self->opt) ) == ( self->value == self->opt ) );
- assert( strlen( self->value ) == self->size );
+ assert( ( self->capacity <= sizeof( self->opt ) ) == ( self->value == self->opt ) );
+ assert( self->value[ self->size ] == 0 );
+ /* String objects modified manually after construction to contain embedded
+ * '\0' characters are considered structurally valid.
+ */
+ assert( strlen( self->value ) <= self->size );
 
- for (i = 0; i < 4; ++i)
+ for ( i = 0; i < 4; ++i )
     {
- assert( self->magic[i] == JAM_STRING_MAGIC );
- assert( self->value[self->capacity + i] == JAM_STRING_MAGIC );
+ assert( self->magic[ i ] == JAM_STRING_MAGIC );
+ assert( self->value[ self->capacity + i ] == JAM_STRING_MAGIC );
     }
 }
 #else
@@ -40,19 +44,21 @@
 # define assert_invariants(x) do {} while (0)
 #endif
 
-void string_new( string* s )
+
+void string_new( string * s )
 {
     s->value = s->opt;
     s->size = 0;
- s->capacity = sizeof(s->opt);
- s->opt[0] = 0;
+ s->capacity = sizeof( s->opt );
+ s->opt[ 0 ] = 0;
 #ifndef NDEBUG
- memset(s->magic, JAM_STRING_MAGIC, sizeof(s->magic));
+ memset( s->magic, JAM_STRING_MAGIC, sizeof( s->magic ) );
 #endif
     assert_invariants( s );
 }
 
-void string_free( string* s )
+
+void string_free( string * s )
 {
     assert_invariants( s );
     if ( s->value != s->opt )
@@ -60,18 +66,21 @@
     string_new( s );
 }
 
-static void string_reserve_internal( string* self, size_t capacity )
+
+static void string_reserve_internal( string * self, size_t capacity )
 {
     if ( self->value == self->opt )
     {
- self->value = (char*)BJAM_MALLOC_ATOMIC( capacity + JAM_STRING_MAGIC_SIZE );
- self->value[0] = 0;
+ self->value = (char *)BJAM_MALLOC_ATOMIC( capacity +
+ JAM_STRING_MAGIC_SIZE );
+ self->value[ 0 ] = 0;
         strncat( self->value, self->opt, sizeof(self->opt) );
- assert( strlen( self->value ) <= self->capacity ); /* This is a regression test */
+ assert( strlen( self->value ) <= self->capacity && "Regression test" );
     }
     else
     {
- self->value = (char*)BJAM_REALLOC( self->value, capacity + JAM_STRING_MAGIC_SIZE );
+ self->value = (char *)BJAM_REALLOC( self->value, capacity +
+ JAM_STRING_MAGIC_SIZE );
     }
 #ifndef NDEBUG
     memcpy( self->value + capacity, self->magic, JAM_STRING_MAGIC_SIZE );
@@ -79,7 +88,8 @@
     self->capacity = capacity;
 }
 
-void string_reserve( string* self, size_t capacity )
+
+void string_reserve( string * self, size_t capacity )
 {
     assert_invariants( self );
     if ( capacity <= self->capacity )
@@ -88,7 +98,8 @@
     assert_invariants( self );
 }
 
-static void extend_full( string* self, char const* start, char const* finish )
+
+static void extend_full( string * self, char const * start, char const * finish )
 {
     size_t new_size = self->capacity + ( finish - start );
     size_t new_capacity = self->capacity;
@@ -97,105 +108,116 @@
         new_capacity <<= 1;
     string_reserve_internal( self, new_capacity );
     memcpy( self->value + old_size, start, new_size - old_size );
- self->value[new_size] = 0;
+ self->value[ new_size ] = 0;
     self->size = new_size;
 }
 
-void string_append( string* self, char const* rhs )
+static void maybe_reserve( string * self, size_t new_size )
 {
- char* p = self->value + self->size;
- char* end = self->value + self->capacity;
+ size_t capacity = self->capacity;
+ if ( capacity <= new_size )
+ {
+ size_t new_capacity = capacity;
+ while ( new_capacity <= new_size )
+ new_capacity <<= 1;
+ string_reserve_internal( self, new_capacity );
+ }
+}
+
+
+void string_append( string * self, char const * rhs )
+{
+ size_t rhs_size = strlen( rhs );
+ size_t new_size = self->size + rhs_size;
     assert_invariants( self );
 
- while ( *rhs && p != end)
- *p++ = *rhs++;
+ maybe_reserve( self, new_size );
+
+ memcpy( self->value + self->size, rhs, rhs_size + 1 );
+ self->size = new_size;
 
- if ( p != end )
- {
- *p = 0;
- self->size = p - self->value;
- }
- else
- {
- extend_full( self, rhs, rhs + strlen(rhs) );
- }
     assert_invariants( self );
 }
 
-void string_append_range( string* self, char const* start, char const* finish )
+
+void string_append_range( string * self, char const * start, char const * finish )
 {
- char* p = self->value + self->size;
- char* end = self->value + self->capacity;
+ size_t rhs_size = finish - start;
+ size_t new_size = self->size + rhs_size;
     assert_invariants( self );
 
- while ( p != end && start != finish )
- *p++ = *start++;
+ maybe_reserve( self, new_size );
+
+ memcpy( self->value + self->size, start, rhs_size );
+ self->size = new_size;
+ self->value[ new_size ] = 0;
 
- if ( p != end )
- {
- *p = 0;
- self->size = p - self->value;
- }
- else
- {
- extend_full( self, start, finish );
- }
     assert_invariants( self );
 }
 
-void string_copy( string* s, char const* rhs )
+
+void string_copy( string * s, char const * rhs )
 {
     string_new( s );
     string_append( s, rhs );
 }
 
-void string_truncate( string* self, size_t n )
+void string_truncate( string * self, size_t n )
 {
     assert_invariants( self );
     assert( n <= self->capacity );
- self->value[self->size = n] = 0;
+ self->value[ self->size = n ] = 0;
     assert_invariants( self );
 }
 
-void string_pop_back( string* self )
+
+void string_pop_back( string * self )
 {
     string_truncate( self, self->size - 1 );
 }
 
-void string_push_back( string* self, char x )
+
+void string_push_back( string * self, char x )
 {
     string_append_range( self, &x, &x + 1 );
 }
 
-char string_back( string* self )
+
+char string_back( string * self )
 {
     assert_invariants( self );
- return self->value[self->size - 1];
+ return self->value[ self->size - 1 ];
 }
 
+
 #ifndef NDEBUG
 void string_unit_test()
 {
- string s[1];
- int i;
- char buffer[sizeof(s->opt) * 2 + 2];
- int limit = sizeof(buffer) > 254 ? 254 : sizeof(buffer);
-
- string_new(s);
-
- for (i = 0; i < limit; ++i)
     {
- string_push_back( s, (char)(i + 1) );
- };
+ string s[ 1 ];
+ int i;
+ int const limit = sizeof( s->opt ) * 2 + 2;
+ string_new( s );
+ assert( s->value == s->opt );
+ for ( i = 0; i < limit; ++i )
+ {
+ string_push_back( s, (char)( i + 1 ) );
+ assert( s->size == i + 1 );
+ }
+ assert( s->size == limit );
+ assert( s->value != s->opt );
+ for ( i = 0; i < limit; ++i )
+ assert( s->value[ i ] == (char)( i + 1 ) );
+ string_free( s );
+ }
 
- for (i = 0; i < limit; ++i)
     {
- assert( i < s->size );
- assert( s->value[i] == (char)(i + 1));
+ char * const original = " \n\t\v Foo \r\n\v \tBar\n\n\r\r\t\n\v\t \t";
+ string copy[ 1 ];
+ string_copy( copy, original );
+ assert( !strcmp( copy->value, original ) );
+ assert( copy->size == strlen( original ) );
+ string_free( copy );
     }
-
- string_free(s);
-
 }
 #endif
-

Modified: branches/release/tools/build/v2/engine/strings.h
==============================================================================
--- branches/release/tools/build/v2/engine/strings.h (original)
+++ branches/release/tools/build/v2/engine/strings.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,34 +1,36 @@
-#ifndef STRINGS_DWA20011024_H
-# define STRINGS_DWA20011024_H
+/*
+ * Copyright 2004. David Abrahams
+ * 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)
+ */
 
-/* Copyright David Abrahams 2004. 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) */
+#ifndef STRINGS_DWA20011024_H
+#define STRINGS_DWA20011024_H
 
-# include <stddef.h>
+#include <stddef.h>
 
 typedef struct string
 {
- char* value;
+ char * value;
     unsigned long size;
     unsigned long capacity;
- char opt[32];
+ char opt[ 32 ];
 #ifndef NDEBUG
- char magic[4];
+ char magic[ 4 ];
 #endif
 } string;
 
-void string_new( string* );
-void string_copy( string*, char const* );
-void string_free( string* );
-void string_append( string*, char const* );
-void string_append_range( string*, char const*, char const* );
-void string_push_back( string* s, char x );
-void string_reserve( string*, size_t );
-void string_truncate( string*, size_t );
-void string_pop_back( string* );
-char string_back( string* );
+void string_new( string * );
+void string_copy( string *, char const * );
+void string_free( string * );
+void string_append( string *, char const * );
+void string_append_range( string *, char const *, char const * );
+void string_push_back( string * s, char x );
+void string_reserve( string *, size_t );
+void string_truncate( string *, size_t );
+void string_pop_back( string * );
+char string_back( string * );
 void string_unit_test();
 
 #endif
-

Modified: branches/release/tools/build/v2/engine/subst.c
==============================================================================
--- branches/release/tools/build/v2/engine/subst.c (original)
+++ branches/release/tools/build/v2/engine/subst.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,103 +1,106 @@
-#include <stddef.h>
 #include "jam.h"
-#include "regexp.h"
-#include "hash.h"
+#include "subst.h"
 
-#include "object.h"
-#include "lists.h"
-#include "compile.h"
-#include "frames.h"
 #include "builtins.h"
+#include "frames.h"
+#include "hash.h"
+#include "lists.h"
 
-struct regex_entry
+#include <stddef.h>
+
+
+typedef struct regex_entry
 {
- OBJECT* pattern;
- regexp* regex;
-};
-typedef struct regex_entry regex_entry;
+ OBJECT * pattern;
+ regexp * regex;
+} regex_entry;
 
-static struct hash* regex_hash;
+static struct hash * regex_hash;
 
-regexp* regex_compile( OBJECT* pattern )
+
+regexp * regex_compile( OBJECT * pattern )
 {
     int found;
     regex_entry * e ;
 
     if ( !regex_hash )
- regex_hash = hashinit(sizeof(regex_entry), "regex");
+ regex_hash = hashinit( sizeof( regex_entry ), "regex" );
 
     e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
     if ( !found )
     {
         e->pattern = object_copy( pattern );
- e->regex = regcomp( (char*)pattern );
+ e->regex = regcomp( (char *)pattern );
     }
 
     return e->regex;
 }
 
+
 LIST * builtin_subst( FRAME * frame, int flags )
 {
- LIST* result = L0;
- LIST* arg1 = lol_get( frame->args, 0 );
- LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
-
- if ( iter != end && list_next( iter ) != end && list_next( list_next( iter ) ) != end )
- {
-
- const char* source = object_str( list_item( iter ) );
- OBJECT * pattern = list_item( list_next( iter ) );
- regexp* repat = regex_compile( pattern );
-
- if ( regexec( repat, (char*)source) )
- {
- LISTITER subst = list_next( iter );
-
- while ( ( subst = list_next( subst ) ) != end )
- {
-# define BUFLEN 4096
- char buf[BUFLEN + 1];
- const char* in = object_str( list_item( subst ) );
- char* out = buf;
-
- for ( ; *in && out < buf + BUFLEN; ++in )
- {
- if ( *in == '\\' || *in == '$' )
- {
- ++in;
- if ( *in == 0 )
- {
- break;
- }
- else if ( *in >= '0' && *in <= '9' )
- {
- unsigned n = *in - '0';
- const size_t srclen = repat->endp[n] - repat->startp[n];
- const size_t remaining = buf + BUFLEN - out;
- const size_t len = srclen < remaining ? srclen : remaining;
- memcpy( out, repat->startp[n], len );
- out += len;
- continue;
- }
- /* fall through and copy the next character */
- }
- *out++ = *in;
- }
- *out = 0;
+ LIST * result = L0;
+ LIST * const arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 );
+ LISTITER const end = list_end( arg1 );
 
- result = list_push_back( result, object_new( buf ) );
+ if ( iter != end && list_next( iter ) != end && list_next( list_next( iter )
+ ) != end )
+ {
+ char const * const source = object_str( list_item( iter ) );
+ OBJECT * const pattern = list_item( list_next( iter ) );
+ regexp * const repat = regex_compile( pattern );
+
+ if ( regexec( repat, (char *)source) )
+ {
+ LISTITER subst = list_next( iter );
+
+ while ( ( subst = list_next( subst ) ) != end )
+ {
+#define BUFLEN 4096
+ char buf[ BUFLEN + 1 ];
+ char const * in = object_str( list_item( subst ) );
+ char * out = buf;
+
+ for ( ; *in && out < buf + BUFLEN; ++in )
+ {
+ if ( *in == '\\' || *in == '$' )
+ {
+ ++in;
+ if ( *in == 0 )
+ break;
+ if ( *in >= '0' && *in <= '9' )
+ {
+ unsigned int const n = *in - '0';
+ size_t const srclen = repat->endp[ n ] -
+ repat->startp[ n ];
+ size_t const remaining = buf + BUFLEN - out;
+ size_t const len = srclen < remaining
+ ? srclen
+ : remaining;
+ memcpy( out, repat->startp[ n ], len );
+ out += len;
+ continue;
+ }
+ /* fall through and copy the next character */
+ }
+ *out++ = *in;
+ }
+ *out = 0;
+
+ result = list_push_back( result, object_new( buf ) );
 #undef BUFLEN
- }
- }
- }
+ }
+ }
+ }
 
- return result;
+ return result;
 }
 
 
 static void free_regex( void * xregex, void * data )
 {
- regex_entry * regex = (regex_entry *)xregex;
+ regex_entry * const regex = (regex_entry *)xregex;
     object_free( regex->pattern );
     BJAM_FREE( regex->regex );
 }

Modified: branches/release/tools/build/v2/engine/timestamp.c
==============================================================================
--- branches/release/tools/build/v2/engine/timestamp.c (original)
+++ branches/release/tools/build/v2/engine/timestamp.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,52 +4,63 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * 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)
  */
 
-# include "jam.h"
-
-# include "hash.h"
-# include "filesys.h"
-# include "pathsys.h"
-# include "timestamp.h"
-# include "object.h"
-# include "strings.h"
-
 /*
  * timestamp.c - get the timestamp of a file or archive member
  *
- * 09/22/00 (seiwald) - downshift names on OS2, too
+ * External routines:
+ * timestamp_from_path() - return timestamp for a path, if present
+ * timestamp_done() - free timestamp tables
+ *
+ * Internal routines:
+ * time_enter() - internal worker callback for scanning archives &
+ * directories
+ * free_timestamps() - worker function for freeing timestamp table contents
  */
 
+#include "jam.h"
+#include "timestamp.h"
+
+#include "filesys.h"
+#include "hash.h"
+#include "object.h"
+#include "pathsys.h"
+#include "strings.h"
+
+
 /*
  * BINDING - all known files
  */
 
-typedef struct _binding BINDING;
-
-struct _binding {
+typedef struct _binding
+{
     OBJECT * name;
- short flags;
+ short flags;
 
-# define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
+#define BIND_SCANNED 0x01 /* if directory or arch, has been scanned */
 
- short progress;
+ short progress;
 
-# define BIND_INIT 0 /* never seen */
-# define BIND_NOENTRY 1 /* timestamp requested but file never found */
-# define BIND_SPOTTED 2 /* file found but not timed yet */
-# define BIND_MISSING 3 /* file found but can't get timestamp */
-# define BIND_FOUND 4 /* file found and time stamped */
+#define BIND_INIT 0 /* never seen */
+#define BIND_NOENTRY 1 /* timestamp requested but file never found */
+#define BIND_SPOTTED 2 /* file found but not timed yet */
+#define BIND_MISSING 3 /* file found but can not get timestamp */
+#define BIND_FOUND 4 /* file found and time stamped */
 
- time_t time; /* update time - 0 if not exist */
-};
+ /* update time - cleared if the there is nothing to bind */
+ timestamp time;
+} BINDING;
 
 static struct hash * bindhash = 0;
-static void time_enter( void *, OBJECT *, int, time_t );
+
+static void time_enter( void *, OBJECT *, int const found,
+ timestamp const * const );
 
 static char * time_progress[] =
 {
@@ -61,130 +72,151 @@
 };
 
 
+#ifdef OS_NT
 /*
- * timestamp() - return timestamp on a file, if present.
+ * timestamp_from_filetime() - Windows FILETIME --> timestamp conversion
+ *
+ * Lifted shamelessly from the CPython implementation.
  */
 
-void timestamp( OBJECT * target, time_t * time )
+void timestamp_from_filetime( timestamp * const t, FILETIME const * const ft )
 {
- PROFILE_ENTER( timestamp );
+ /* Seconds between 1.1.1601 and 1.1.1970 */
+ static __int64 const secs_between_epochs = 11644473600;
 
- PATHNAME f1;
- PATHNAME f2;
- int found;
- BINDING * b;
- string buf[ 1 ];
+ /* We can not simply cast and dereference a FILETIME, since it might not be
+ * aligned properly. __int64 type variables are expected to be aligned to an
+ * 8 byte boundary while FILETIME structures may be aligned to any 4 byte
+ * boundary. Using an incorrectly aligned __int64 variable may cause a
+ * performance penalty on some platforms or even exceptions on others
+ * (documented on MSDN).
+ */
+ __int64 in;
+ memcpy( &in, ft, sizeof( in ) );
+
+ /* FILETIME resolution: 100ns. */
+ timestamp_init( t, (time_t)( ( in / 10000000 ) - secs_between_epochs ),
+ (int)( in % 10000000 ) * 100 );
+}
+#endif /* OS_NT */
 
- target = path_as_key( target );
 
- string_new( buf );
+void timestamp_clear( timestamp * const time )
+{
+ time->secs = time->nsecs = 0;
+}
 
- if ( !bindhash )
- bindhash = hashinit( sizeof( BINDING ), "bindings" );
 
- /* Quick path - is it there? */
+int timestamp_cmp( timestamp const * const lhs, timestamp const * const rhs )
+{
+ return lhs->secs == rhs->secs
+ ? lhs->nsecs - rhs->nsecs
+ : lhs->secs - rhs->secs;
+}
 
- b = (BINDING *)hash_insert( bindhash, target, &found );
- if ( !found )
- {
- b->name = object_copy( target ); /* never freed */
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
- }
 
- if ( b->progress != BIND_INIT )
- goto afterscanning;
+void timestamp_copy( timestamp * const target, timestamp const * const source )
+{
+ target->secs = source->secs;
+ target->nsecs = source->nsecs;
+}
 
- b->progress = BIND_NOENTRY;
 
- /* Not found - have to scan for it. */
- path_parse( object_str( target ), &f1 );
+void timestamp_current( timestamp * const t )
+{
+#ifdef OS_NT
+ /* GetSystemTimeAsFileTime()'s resolution seems to be about 15 ms on Windows
+ * XP and under a millisecond on Windows 7.
+ */
+ FILETIME ft;
+ GetSystemTimeAsFileTime( &ft );
+ timestamp_from_filetime( t, &ft );
+#else /* OS_NT */
+ timestamp_init( t, time( 0 ), 0 );
+#endif /* OS_NT */
+}
 
- /* Scan directory if not already done so. */
- {
- int found;
- BINDING * b;
- OBJECT * name;
-
- f2 = f1;
- f2.f_grist.len = 0;
- path_parent( &f2 );
- path_build( &f2, buf, 0 );
-
- name = object_new( buf->value );
-
- b = (BINDING *)hash_insert( bindhash, name, &found );
- if ( !found )
- {
- b->name = object_copy( name );
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
- }
-
- if ( !( b->flags & BIND_SCANNED ) )
- {
- file_dirscan( name, time_enter, bindhash );
- b->flags |= BIND_SCANNED;
- }
 
- object_free( name );
- }
+int timestamp_empty( timestamp const * const time )
+{
+ return !time->secs && !time->nsecs;
+}
 
- /* Scan archive if not already done so. */
- if ( f1.f_member.len )
- {
- int found;
- BINDING * b;
- OBJECT * name;
-
- f2 = f1;
- f2.f_grist.len = 0;
- f2.f_member.len = 0;
- string_truncate( buf, 0 );
- path_build( &f2, buf, 0 );
-
- name = object_new( buf->value );
-
- b = (BINDING *)hash_insert( bindhash, name, &found );
- if ( !found )
- {
- b->name = object_copy( name );
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
- }
-
- if ( !( b->flags & BIND_SCANNED ) )
- {
- file_archscan( buf->value, time_enter, bindhash );
- b->flags |= BIND_SCANNED;
- }
 
- object_free( name );
- }
+/*
+ * timestamp_from_path() - return timestamp for a path, if present
+ */
 
- afterscanning:
+void timestamp_from_path( timestamp * const time, OBJECT * const path )
+{
+ PROFILE_ENTER( timestamp );
 
- if ( b->progress == BIND_SPOTTED )
- {
- b->progress = file_time( b->name, &b->time ) < 0
- ? BIND_MISSING
- : BIND_FOUND;
- }
+ PATHNAME f1;
+ PATHNAME f2;
+ int found;
+ BINDING * b;
+ string buf[ 1 ];
 
- *time = b->progress == BIND_FOUND ? b->time : 0;
- string_free( buf );
 
- object_free( target );
+ if ( file_time( path, time ) < 0 )
+ timestamp_clear( time );
 
     PROFILE_EXIT( timestamp );
 }
 
 
-static void time_enter( void * closure, OBJECT * target, int found, time_t time )
+void timestamp_init( timestamp * const time, time_t const secs, int const nsecs
+ )
+{
+ time->secs = secs;
+ time->nsecs = nsecs;
+}
+
+
+void timestamp_max( timestamp * const max, timestamp const * const lhs,
+ timestamp const * const rhs )
+{
+ if ( timestamp_cmp( lhs, rhs ) > 0 )
+ timestamp_copy( max, lhs );
+ else
+ timestamp_copy( max, rhs );
+}
+
+
+static char const * timestamp_formatstr( timestamp const * const time,
+ char const * const format )
+{
+ static char result1[ 500 ];
+ static char result2[ 500 ];
+ strftime( result1, sizeof( result1 ) / sizeof( *result1 ), format, gmtime(
+ &time->secs ) );
+ sprintf( result2, result1, time->nsecs );
+ return result2;
+}
+
+
+char const * timestamp_str( timestamp const * const time )
+{
+ return timestamp_formatstr( time, "%Y-%m-%d %H:%M:%S.%%09d +0000" );
+}
+
+
+char const * timestamp_timestr( timestamp const * const time )
+{
+ return timestamp_formatstr( time, "%H:%M:%S.%%09d" );
+}
+
+
+/*
+ * time_enter() - internal worker callback for scanning archives & directories
+ */
+
+static void time_enter( void * closure, OBJECT * target, int const found,
+ timestamp const * const time )
 {
     int item_found;
     BINDING * b;
- struct hash * bindhash = (struct hash *)closure;
+ struct hash * const bindhash = (struct hash *)closure;
 
     target = path_as_key( target );
 
@@ -195,29 +227,36 @@
         b->flags = 0;
     }
 
- b->time = time;
+ timestamp_copy( &b->time, time );
     b->progress = found ? BIND_FOUND : BIND_SPOTTED;
 
     if ( DEBUG_BINDSCAN )
- printf( "time ( %s ) : %s\n", object_str( target ), time_progress[ b->progress ] );
+ printf( "time ( %s ) : %s\n", object_str( target ), time_progress[
+ b->progress ] );
 
     object_free( target );
 }
 
-static void free_timestamps ( void * xbinding, void * data )
+
+/*
+ * free_timestamps() - worker function for freeing timestamp table contents
+ */
+
+static void free_timestamps( void * xbinding, void * data )
 {
- object_free( ((BINDING *)xbinding)->name );
+ object_free( ( (BINDING *)xbinding )->name );
 }
 
+
 /*
- * stamps_done() - free timestamp tables.
+ * timestamp_done() - free timestamp tables
  */
 
-void stamps_done()
+void timestamp_done()
 {
     if ( bindhash )
     {
- hashenumerate( bindhash, free_timestamps, (void *)0 );
+ hashenumerate( bindhash, free_timestamps, 0 );
         hashdone( bindhash );
     }
 }

Modified: branches/release/tools/build/v2/engine/timestamp.h
==============================================================================
--- branches/release/tools/build/v2/engine/timestamp.h (original)
+++ branches/release/tools/build/v2/engine/timestamp.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,9 +12,36 @@
 #define TIMESTAMP_H_SW_2011_11_18
 
 #include "object.h"
-#include "time.h"
 
-void timestamp( OBJECT * target, time_t * time );
-void stamps_done();
+#ifdef OS_NT
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+
+#include <time.h>
+
+typedef struct timestamp
+{
+ time_t secs;
+ int nsecs;
+} timestamp;
+
+void timestamp_clear( timestamp * const );
+int timestamp_cmp( timestamp const * const lhs, timestamp const * const rhs );
+void timestamp_copy( timestamp * const target, timestamp const * const source );
+void timestamp_current( timestamp * const );
+int timestamp_empty( timestamp const * const );
+void timestamp_from_path( timestamp * const, OBJECT * const path );
+void timestamp_init( timestamp * const, time_t const secs, int const nsecs );
+void timestamp_max( timestamp * const max, timestamp const * const lhs,
+ timestamp const * const rhs );
+char const * timestamp_str( timestamp const * const );
+char const * timestamp_timestr( timestamp const * const );
+
+#ifdef OS_NT
+void timestamp_from_filetime( timestamp * const, FILETIME const * const );
+#endif
+
+void timestamp_done();
 
 #endif

Modified: branches/release/tools/build/v2/engine/variable.c
==============================================================================
--- branches/release/tools/build/v2/engine/variable.c (original)
+++ branches/release/tools/build/v2/engine/variable.c 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,51 +4,46 @@
  * This file is part of Jam - see jam.c for Copyright information.
  */
 
-/* This file is ALSO:
- * Copyright 2001-2004 David Abrahams.
- * Copyright 2005 Reece H. Dunn.
- * Copyright 2005 Rene Rivera.
- * 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)
+/* This file is ALSO:
+ * Copyright 2001-2004 David Abrahams.
+ * Copyright 2005 Reece H. Dunn.
+ * Copyright 2005 Rene Rivera.
+ * 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)
  */
 
-#include "jam.h"
-#include "lists.h"
-#include "parse.h"
-#include "variable.h"
-#include "hash.h"
-#include "filesys.h"
-#include "object.h"
-#include "strings.h"
-#include "pathsys.h"
-#include "modules.h"
-#include <stdlib.h>
-#include <stdio.h>
-
 /*
  * variable.c - handle Jam multi-element variables.
  *
  * External routines:
  *
- * var_defines() - load a bunch of variable=value settings.
- * var_string() - expand a string with variables in it.
- * var_get() - get value of a user defined symbol.
+ * var_defines() - load a bunch of variable=value settings
+ * var_get() - get value of a user defined symbol
  * var_set() - set a variable in jam's user defined symbol table.
- * var_swap() - swap a variable's value with the given one.
- * var_done() - free variable tables.
+ * var_swap() - swap a variable's value with the given one
+ * var_done() - free variable tables
  *
  * Internal routines:
  *
- * var_enter() - make new var symbol table entry, returning var ptr.
- * var_dump() - dump a variable to stdout.
- *
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 08/23/94 (seiwald) - Support for '+=' (append to variable)
- * 01/22/95 (seiwald) - split environment variables at blanks or :'s
- * 05/10/95 (seiwald) - split path variables at SPLITPATH (not :)
- * 09/11/00 (seiwald) - defunct var_list() removed
+ * var_enter() - make new var symbol table entry, returning var ptr
+ * var_dump() - dump a variable to stdout
  */
 
+#include "jam.h"
+#include "variable.h"
+
+#include "filesys.h"
+#include "hash.h"
+#include "modules.h"
+#include "parse.h"
+#include "pathsys.h"
+#include "strings.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
 /*
  * VARIABLE - a user defined multi-value variable
  */
@@ -61,7 +56,7 @@
     LIST * value;
 };
 
-static LIST * * var_enter( struct module_t * module, OBJECT * symbol );
+static LIST * * var_enter( struct module_t *, OBJECT * symbol );
 static void var_dump( OBJECT * symbol, LIST * value, char * what );
 
 
@@ -70,49 +65,32 @@
  *
  * If preprocess is false, take the value verbatim.
  *
- * Otherwise, if the variable value is enclosed in quotes, strip the
- * quotes.
- *
+ * Otherwise, if the variable value is enclosed in quotes, strip the quotes.
  * Otherwise, if variable name ends in PATH, split value at :'s.
- *
  * Otherwise, split the value at blanks.
  */
 
 void var_defines( struct module_t * module, char * const * e, int preprocess )
 {
- string buf[1];
+ string buf[ 1 ];
 
     string_new( buf );
 
     for ( ; *e; ++e )
     {
         char * val;
- OBJECT * varname;
 
-# ifdef OS_MAC
- /* On the mac (MPW), the var=val is actually var\0val */
- /* Think different. */
-
- if ( ( val = strchr( *e, '=' ) ) || ( val = *e + strlen( *e ) ) )
-# else
- if ( ( val = strchr( *e, '=' ) ) )
-# endif
+ if ( ( val = strchr( *e, '=' ) )
+#if defined( OS_MAC )
+ /* On the mac (MPW), the var=val is actually var\0val */
+ /* Think different. */
+ || ( val = *e + strlen( *e ) )
+#endif
+ )
         {
             LIST * l = L0;
- char * pp;
- char * p;
-# ifdef OPT_NO_EXTERNAL_VARIABLE_SPLIT
- char split = '\0';
-# else
- # ifdef OS_MAC
- char split = ',';
- # else
- char split = ' ';
- # endif
-# endif
- size_t len = strlen( val + 1 );
-
- int quoted = ( val[1] == '"' ) && ( val[len] == '"' ) &&
+ size_t const len = strlen( val + 1 );
+ int const quoted = ( val[ 1 ] == '"' ) && ( val[ len ] == '"' ) &&
                 ( len > 1 );
 
             if ( quoted && preprocess )
@@ -123,6 +101,18 @@
             }
             else
             {
+ char * p;
+ char * pp;
+ char split =
+#if defined( OPT_NO_EXTERNAL_VARIABLE_SPLIT )
+ '\0'
+#elif defined( OS_MAC )
+ ','
+#else
+ ' '
+#endif
+ ;
+
                 /* Split *PATH at :'s, not spaces. */
                 if ( val - 4 >= *e )
                 {
@@ -150,9 +140,11 @@
 
             /* Get name. */
             string_append_range( buf, *e, val );
- varname = object_new( buf->value );
- var_set( module, varname, l, VAR_SET );
- object_free( varname );
+ {
+ OBJECT * const varname = object_new( buf->value );
+ var_set( module, varname, l, VAR_SET );
+ object_free( varname );
+ }
             string_truncate( buf, 0 );
         }
     }
@@ -160,10 +152,12 @@
 }
 
 
+/* Last returned variable value saved so we may clear it in var_done(). */
 static LIST * saved_var = L0;
 
+
 /*
- * var_get() - get value of a user defined symbol.
+ * var_get() - get value of a user defined symbol
  *
  * Returns NULL if symbol unset.
  */
@@ -176,7 +170,7 @@
     if ( object_equal( symbol, constant_TMPDIR ) )
     {
         list_free( saved_var );
- result = saved_var = list_new( object_new( path_tmpdir() ) );
+ result = saved_var = list_new( object_new( path_tmpdir()->value ) );
     }
     else if ( object_equal( symbol, constant_TMPNAME ) )
     {
@@ -210,7 +204,8 @@
                 var_dump( symbol, module->fixed_variables[ n ], "get" );
             result = module->fixed_variables[ n ];
         }
- else if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ else if ( module->variables && ( v = (VARIABLE *)hash_find(
+ module->variables, symbol ) ) )
         {
             if ( DEBUG_VARGET )
                 var_dump( v->symbol, v->value, "get" );
@@ -226,7 +221,8 @@
     LIST * result = L0;
     VARIABLE * v;
 
- if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables,
+ symbol ) ) )
     {
         result = v->value;
         v->value = L0;
@@ -235,8 +231,9 @@
     return result;
 }
 
+
 /*
- * var_set() - set a variable in Jam's user defined symbol table.
+ * var_set() - set a variable in Jam's user defined symbol table
  *
  * 'flag' controls the relationship between new and old values of the variable:
  * SET replaces the old with the new; APPEND appends the new to the old; DEFAULT
@@ -245,7 +242,8 @@
  * Copies symbol. Takes ownership of value.
  */
 
-void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag )
+void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag
+ )
 {
     LIST * * v = var_enter( module, symbol );
 
@@ -254,19 +252,16 @@
 
     switch ( flag )
     {
- case VAR_SET:
- /* Replace value */
+ case VAR_SET: /* Replace value */
         list_free( *v );
         *v = value;
         break;
 
- case VAR_APPEND:
- /* Append value */
+ case VAR_APPEND: /* Append value */
         *v = list_append( *v, value );
         break;
 
- case VAR_DEFAULT:
- /* Set only if unset */
+ case VAR_DEFAULT: /* Set only if unset */
         if ( list_empty( *v ) )
             *v = value;
         else
@@ -277,13 +272,13 @@
 
 
 /*
- * var_swap() - swap a variable's value with the given one.
+ * var_swap() - swap a variable's value with the given one
  */
 
 LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
 {
     LIST * * v = var_enter( module, symbol );
- LIST * oldvalue = *v;
+ LIST * oldvalue = *v;
     if ( DEBUG_VARSET )
         var_dump( symbol, value, "set" );
     *v = value;
@@ -292,7 +287,7 @@
 
 
 /*
- * var_enter() - make new var symbol table entry, returning var ptr.
+ * var_enter() - make new var symbol table entry, returning var ptr
  */
 
 static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
@@ -302,9 +297,7 @@
     int n;
 
     if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
- {
         return &module->fixed_variables[ n ];
- }
 
     if ( !module->variables )
         module->variables = hashinit( sizeof( VARIABLE ), "variables" );
@@ -321,7 +314,7 @@
 
 
 /*
- * var_dump() - dump a variable to stdout.
+ * var_dump() - dump a variable to stdout
  */
 
 static void var_dump( OBJECT * symbol, LIST * value, char * what )
@@ -333,21 +326,20 @@
 
 
 /*
- * var_done() - free variable tables.
+ * var_done() - free variable tables
  */
 
 static void delete_var_( void * xvar, void * data )
 {
- VARIABLE * v = (VARIABLE *)xvar;
+ VARIABLE * const v = (VARIABLE *)xvar;
     object_free( v->symbol );
- list_free( v-> value );
+ list_free( v->value );
 }
 
-
 void var_done( struct module_t * module )
 {
     list_free( saved_var );
     saved_var = L0;
- hashenumerate( module->variables, delete_var_, (void *)0 );
+ hashenumerate( module->variables, delete_var_, 0 );
     hash_free( module->variables );
 }

Modified: branches/release/tools/build/v2/engine/variable.h
==============================================================================
--- branches/release/tools/build/v2/engine/variable.h (original)
+++ branches/release/tools/build/v2/engine/variable.h 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,20 +11,24 @@
 #ifndef VARIABLE_SW20111119_H
 #define VARIABLE_SW20111119_H
 
+#include "lists.h"
+#include "object.h"
+
+
 struct module_t;
 
-void var_defines( struct module_t * module, char * const * e, int preprocess );
-LIST * var_get( struct module_t * module, OBJECT * symbol );
-void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag );
-LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value );
-void var_done( struct module_t * module );
+void var_defines( struct module_t *, char * const * e, int preprocess );
+LIST * var_get( struct module_t *, OBJECT * symbol );
+void var_set( struct module_t *, OBJECT * symbol, LIST * value, int flag );
+LIST * var_swap( struct module_t *, OBJECT * symbol, LIST * value );
+void var_done( struct module_t * );
 
 /*
  * Defines for var_set().
  */
 
-# define VAR_SET 0 /* override previous value */
-# define VAR_APPEND 1 /* append to previous value */
-# define VAR_DEFAULT 2 /* set only if no previous value */
+#define VAR_SET 0 /* override previous value */
+#define VAR_APPEND 1 /* append to previous value */
+#define VAR_DEFAULT 2 /* set only if no previous value */
 
 #endif

Modified: branches/release/tools/build/v2/hacking.txt
==============================================================================
--- branches/release/tools/build/v2/hacking.txt (original)
+++ branches/release/tools/build/v2/hacking.txt 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -23,11 +23,11 @@
 Additional resources include
 
    - The issue tracker
- http://zigzag.cs.msu.su/boost.build
+ http://trac.lvk.cs.msu.su/boost.build/
 
- - commits mailing list:
- boost-build_at_[hidden]
- http://sourceforge.net/mailarchive/forum.php?forum_id=9097
+ - mailing list:
+ boost-build_at_[hidden]
+ http://lists.boost.org/boost-build/
 
 
 BUGS and PATCHES
@@ -136,19 +136,3 @@
         {
             #
         }
-
-HTML DOCUMENTATION.
-
- Please pass HTML files though HTML Tidy (http://tidy.sf.net) before
- comitting. This has to important purposes:
- - detecting bad HTML
- - converting files to uniform indentation style, which inverses effect of
- different editors and makes differences between revisions much smaller and
- easy for review.
-
- Alas, the way Tidy indents HTML differs between version. Please use the
- version available at
-
- http://tidy.sourceforge.net/src/old/tidy_src_020411.tgz
-
- and "-i -wrap 78" command line parameters.

Modified: branches/release/tools/build/v2/kernel/bootstrap.jam
==============================================================================
--- branches/release/tools/build/v2/kernel/bootstrap.jam (original)
+++ branches/release/tools/build/v2/kernel/bootstrap.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,11 +1,11 @@
-# Copyright 2003 Dave Abrahams
-# Copyright 2003, 2005, 2006 Rene Rivera
-# Copyright 2003, 2005, 2006 Vladimir Prus
-# 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)
-
-# First of all, check the jam version
+# Copyright 2003 Dave Abrahams
+# Copyright 2003, 2005, 2006 Rene Rivera
+# Copyright 2003, 2005, 2006 Vladimir Prus
+# 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)
 
+# First of all, check the jam version.
 if $(JAM_VERSION:J="") < 030112
 {
     ECHO "error: Boost.Jam version 3.1.12 or later required" ;
@@ -13,7 +13,6 @@
 }
 
 local required-rules = GLOB-RECURSIVELY HAS_NATIVE_RULE ;
-
 for local r in $(required-rules)
 {
     if ! $(r) in [ RULENAMES ]
@@ -25,14 +24,10 @@
     }
 }
 
-local native =
- regex transform 2
- ;
+local native = regex transform 2 ;
 while $(native)
 {
- if ! [ HAS_NATIVE_RULE $(native[1]) :
- $(native[2]) :
- $(native[3]) ]
+ if ! [ HAS_NATIVE_RULE $(native[1]) : $(native[2]) : $(native[3]) ]
     {
         ECHO "error: missing native rule '$(native[1]).$(native[2])'" ;
         ECHO "error: or interface version of that rule is too low" ;
@@ -43,10 +38,11 @@
     native = $(native[4-]) ;
 }
 
-# Check that the builtin .ENVIRON module is present. We don't have a
-# builtin to check that a module is present, so we assume that the PATH
-# environment variable is always set and verify that the .ENVIRON module
-# has non-empty value of that variable.
+
+# Check that the builtin .ENVIRON module is present. We do not have a builtin to
+# check that a module is present, so we assume that the PATH environment
+# variable is always set and verify that the .ENVIRON module has a non-empty
+# value of that variable.
 module .ENVIRON
 {
     local p = $(PATH) $(Path) $(path) ;
@@ -59,15 +55,15 @@
     }
 }
 
-# Check that @() functionality is present. Similarly to modules,
-# we don't have a way to test that directly. Instead we check that
-# $(TMPNAME) functionality is present which was added at roughly
-# the same time (more precisely it was added just before).
+# Check that @() functionality is present. Similarly to modules, we do not have
+# a way to test this directly. Instead we check that $(TMPNAME) functionality is
+# present which was added at roughly the same time (more precisely, it was added
+# just before).
 {
     if ! $(TMPNAME)
     {
         ECHO "error: no @() functionality found" ;
- ECHO "error: your version of bjam is likely out of date" ;
+ ECHO "error: your version of b2 is likely out of date" ;
         ECHO "error: please get a fresh version from SVN." ;
         EXIT ;
     }
@@ -76,15 +72,16 @@
 # Make sure that \n escape is avaiable.
 if "\n" = "n"
 {
- if $(OS) = CYGWIN
- {
+ if $(OS) = CYGWIN
+ {
         ECHO "warning: escape sequences are not supported" ;
         ECHO "warning: this will cause major misbehaviour on cygwin" ;
- ECHO "warning: your version of bjam is likely out of date" ;
+ ECHO "warning: your version of b2 is likely out of date" ;
         ECHO "warning: please get a fresh version from SVN." ;
- }
+ }
 }
 
+
 # Bootstrap the module system. Then bring the import rule into the global module.
 #
 SEARCH on <module@>modules.jam = $(.bootstrap-file:D) ;
@@ -92,71 +89,70 @@
 IMPORT modules : import : : import ;
 
 {
- # Add module subdirectories to the BOOST_BUILD_PATH, which allows
- # us to make an incremental refactoring step by moving modules to
- # the appropriate subdirectories, thereby achieving some physical
- # separation of different layers without changing all of our code
- # to specify subdirectories in import statements or use an extra
- # level of qualification on imported names.
+ # Add module subdirectories to the BOOST_BUILD_PATH, which allows us to make
+ # incremental refactoring steps by moving modules to appropriate
+ # subdirectories, thereby achieving some physical separation of different
+ # layers without changing all of our code to specify subdirectories in
+ # import statements or use an extra level of qualification on imported
+ # names.
 
     local subdirs =
- kernel # only the most-intrinsic modules: modules, errors
- util # low-level substrate: string/number handling, etc.
- build # essential elements of the build system architecture
- tools # toolsets for handling specific build jobs and targets.
- contrib # user contributed (unreviewed) modules
- . # build-system.jam lives here
- ;
+ kernel # only the most-intrinsic modules: modules, errors
+ util # low-level substrate: string/number handling, etc.
+ build # essential elements of the build system architecture
+ tools # toolsets for handling specific build jobs and targets.
+ contrib # user contributed (unreviewed) modules
+ . # build-system.jam lives here
+ ;
     local whereami = [ NORMALIZE_PATH $(.bootstrap-file:DT) ] ;
     BOOST_BUILD_PATH += $(whereami:D)/$(subdirs) ;
 
     modules.poke .ENVIRON : BOOST_BUILD_PATH : $(BOOST_BUILD_PATH) ;
-
+
     modules.poke : EXTRA_PYTHONPATH : $(whereami) ;
 }
 
-# Reload the modules, to clean up things. The modules module can tolerate
-# being included twice.
+# Reload the modules, to clean up things. The modules module can tolerate being
+# imported twice.
 #
 import modules ;
 
-# Process option plugins first to alow them to prevent loading
-# the rest of the build system.
+# Process option plugins first to allow them to prevent loading the rest of the
+# build system.
 #
 import option ;
 local dont-build = [ option.process ] ;
 
-# Should we skip building, i.e. loading the build system, according
-# to the options processed?
+# Should we skip building, i.e. loading the build system, according to the
+# options processed?
 #
 if ! $(dont-build)
 {
     if ! --python in $(ARGV)
     {
- # Allow users to override the build system file from the
- # command-line (mostly for testing)
+ # Allow users to override the build system file from the command-line
+ # (mostly for testing).
         local build-system = [ MATCH --build-system=(.*) : $(ARGV) ] ;
         build-system ?= build-system ;
 
- # Use last element in case of multiple command-line options
+ # Use last element in case of multiple command-line options.
         import $(build-system[-1]) ;
     }
     else
     {
         ECHO "Boost.Build V2 Python port (experimental)" ;
-
- # Define additional interface that is exposed to Python code. Python code will
- # also have access to select bjam builtins in the 'bjam' module, but some
- # things are easier to define outside C.
+
+ # Define additional interface exposed to Python code. Python code will
+ # also have access to select bjam builtins in the 'bjam' module, but
+ # some things are easier to define outside C.
         module python_interface
         {
             rule load ( module-name : location )
- {
+ {
                 USER_MODULE $(module-name) ;
- # Make all rules in the loaded module available in
- # the global namespace, so that we don't have
- # to bother specifying "right" module when calling
- # from Python.
+ # Make all rules in the loaded module available in the global
+ # namespace, so that we do not have to bother specifying the
+ # "correct" module when calling from Python.
                 module $(module-name)
                 {
                     __name__ = $(1) ;
@@ -164,8 +160,8 @@
                     local rules = [ RULENAMES $(1) ] ;
                     IMPORT $(1) : $(rules) : $(1) : $(1).$(rules) ;
                 }
- }
-
+ }
+
             rule peek ( module-name ? : variables + )
             {
                 module $(<)
@@ -173,66 +169,74 @@
                     return $($(>)) ;
                 }
             }
-
+
             rule set-variable ( module-name : name : value * )
             {
                 module $(<)
                 {
                     $(>) = $(3) ;
- }
+ }
             }
-
+
             rule set-top-level-targets ( targets * )
             {
                 DEPENDS all : $(targets) ;
             }
-
+
             rule call-in-module ( m : rulename : * )
             {
                 module $(m)
                 {
- return [ $(2) $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
- }
+ return [ $(2) $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9)
+ : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16)
+ : $(17) : $(18) : $(19) ] ;
+ }
             }
 
-
- rule set-update-action ( action : targets * : sources * : properties * )
+
+ rule set-update-action ( action : targets * : sources * :
+ properties * )
             {
                 $(action) $(targets) : $(sources) : $(properties) ;
             }
-
- rule set-update-action-in-module ( m : action : targets * : sources * : properties * )
+
+ rule set-update-action-in-module ( m : action : targets * :
+ sources * : properties * )
             {
                 module $(m)
                 {
                     $(2) $(3) : $(4) : $(5) ;
- }
+ }
             }
-
- rule set-target-variable ( targets + : variable : value * : append ? )
+
+ rule set-target-variable ( targets + : variable : value * : append ?
+ )
             {
                 if $(append)
- {
- $(variable) on $(targets) += $(value) ;
+ {
+ $(variable) on $(targets) += $(value) ;
                 }
                 else
                 {
- $(variable) on $(targets) = $(value) ;
- }
- }
+ $(variable) on $(targets) = $(value) ;
+ }
+ }
 
             rule get-target-variable ( targets + : variable )
             {
                 return [ on $(targets) return $($(variable)) ] ;
             }
 
- rule import-rules-from-parent ( parent-module : this-module : user-rules * )
+ rule import-rules-from-parent ( parent-module : this-module :
+ user-rules * )
             {
- IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules) ;
+ IMPORT $(parent-module) : $(user-rules) : $(this-module) :
+ $(user-rules) ;
                 EXPORT $(this-module) : $(user-rules) ;
             }
 
- rule mark-included ( targets * : includes * ) {
+ rule mark-included ( targets * : includes * )
+ {
                 NOCARE $(includes) ;
                 INCLUDES $(targets) : $(includes) ;
                 ISFILE $(includes) ;
@@ -241,23 +245,22 @@
 
         PYTHON_IMPORT_RULE bootstrap : bootstrap : PyBB : bootstrap ;
         modules.poke PyBB : root : [ NORMALIZE_PATH $(.bootstrap-file:DT)/.. ] ;
-
+
         module PyBB
         {
             local ok = [ bootstrap $(root) ] ;
             if ! $(ok)
             {
                 EXIT ;
- }
+ }
         }
-
-
+
+
         #PYTHON_IMPORT_RULE boost.build.build_system : main : PyBB : main ;
 
         #module PyBB
- #{
+ #{
         # main ;
         #}
-
     }
 }

Modified: branches/release/tools/build/v2/kernel/class.jam
==============================================================================
--- branches/release/tools/build/v2/kernel/class.jam (original)
+++ branches/release/tools/build/v2/kernel/class.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,11 +2,12 @@
 # Copyright 2002, 2005 Rene Rivera
 # Copyright 2002, 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Polymorphic class system built on top of core Jam facilities.
 #
-# Classes are defined by 'class' keywords::
+# Classes are defined by 'class' keywords:
 #
 # class myclass
 # {
@@ -81,11 +82,12 @@
     .next-instance ?= 1 ;
     local id = object($(class))@$(.next-instance) ;
 
- xinit $(id) : $(class) ;
-
     INSTANCE $(id) : class@$(class) ;
+ xinit $(id) : $(class) ;
     IMPORT_MODULE $(id) ;
- $(id).__init__ $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ $(id).__init__ $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) :
+ $(18) : $(19) ;
 
     # Bump the next unique object name.
     .next-instance = [ numbers.increment $(.next-instance) ] ;
@@ -163,6 +165,7 @@
 {
     import assert ;
     import "class" : new ;
+ import errors : try catch ;
 
     # This will be the construction function for a class called 'myclass'.
     #
@@ -238,8 +241,7 @@
         {
             return $(foo) ;
         }
- }
-# class myclass ;
+ } # class myclass ;
 
     class derived1 : myclass
     {
@@ -281,8 +283,7 @@
             local v = 10 ;
             assert.variable-not-empty v ;
         }
- }
-# class derived1 : myclass ;
+ } # class derived1 : myclass ;
 
     class derived2 : myclass
     {
@@ -304,8 +305,7 @@
         {
             return [ myclass.get-x ] ;
         }
- }
-# class derived2 : myclass ;
+ } # class derived2 : myclass ;
 
     class derived2a : derived2
     {
@@ -313,8 +313,7 @@
         {
             derived2.__init__ ;
         }
- }
-# class derived2a : derived2 ;
+ } # class derived2a : derived2 ;
 
     local rule expect_derived2 ( [derived2] x ) { }
 
@@ -348,7 +347,8 @@
     # new bad_subclass ;
     #}
     #catch
- # bad_subclass.bad_subclass failed to call base class constructor myclass.__init__
+ # bad_subclass.bad_subclass failed to call base class constructor
+ # myclass.__init__
     # ;
 
     #try ;

Modified: branches/release/tools/build/v2/kernel/errors.jam
==============================================================================
--- branches/release/tools/build/v2/kernel/errors.jam (original)
+++ branches/release/tools/build/v2/kernel/errors.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,7 +1,8 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2004 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Print a stack backtrace leading to this rule's caller. Each argument
 # represents a line of output to be printed after the first line of the
@@ -13,8 +14,8 @@
     local drop-elements = $(frame-skips[$(skip-frames)]) ;
     if ! ( $(skip-frames) in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 )
     {
- ECHO "warning: backtrace doesn't support skipping $(skip-frames) frames;"
- "using 1 instead." ;
+ ECHO "warning: backtrace doesn't support skipping $(skip-frames) "
+ "frames; using 1 instead." ;
         drop-elements = 5 ;
     }
 
@@ -22,10 +23,13 @@
     if $(.user-modules-only)
     {
         local bt = [ nearest-user-location ] ;
- ECHO "$(prefix) at $(bt) " ;
+ if $(bt)
+ {
+ ECHO $(prefix) at $(bt) ;
+ }
         for local n in $(args)
         {
- if $($(n))-is-not-empty
+ if $($(n))-is-defined
             {
                 ECHO $(prefix) $($(n)) ;
             }
@@ -46,7 +50,7 @@
             # The first time through, print each argument on a separate line.
             for local n in $(args)
             {
- if $($(n))-is-not-empty
+ if $($(n))-is-defined
                 {
                     ECHO $(prefix) $($(n)) ;
                 }
@@ -59,7 +63,7 @@
     }
 }
 
-.args ?= messages 2 3 4 5 6 7 8 9 ;
+.args ?= messages 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;
 .disabled ?= ;
 .last-error-$(.args) ?= ;
 
@@ -89,7 +93,7 @@
 
     import sequence ;
 
- if ! $(.last-error-$(.args))-is-not-empty
+ if ! $(.last-error-$(.args))-is-defined
     {
         error-skip-frames 3 expected an error, but none occurred ;
     }
@@ -116,15 +120,17 @@
 {
     if ! $(.disabled)
     {
- backtrace $(skip-frames) error: $(messages) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ backtrace $(skip-frames) error: $(messages) : $(2) : $(3) : $(4) : $(5)
+ : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14)
+ : $(15) : $(16) : $(17) : $(18) : $(19) ;
         EXIT ;
     }
     else if ! $(.last-error-$(.args))
     {
         for local n in $(.args)
         {
- # Add an extra empty string so that we always have
- # something in the event of an error
+ # Add an extra empty string so that we always have something in the
+ # event of an error.
             .last-error-$(n) = $($(n)) "" ;
         }
     }
@@ -142,10 +148,11 @@
 {
     if $(.no-error-backtrace)
     {
+ local first-printed ;
         # Print each argument on a separate line.
         for local n in $(.args)
         {
- if $($(n))-is-not-empty
+ if $($(n))-is-defined
             {
                 if ! $(first-printed)
                 {
@@ -162,7 +169,9 @@
     }
     else
     {
- error-skip-frames 3 $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ error-skip-frames 3 $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) :
+ $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16)
+ : $(17) : $(18) : $(19) ;
     }
 }
 
@@ -172,7 +181,9 @@
 rule user-error ( messages * : * )
 {
     .user-modules-only = 1 ;
- error-skip-frames 3 $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ error-skip-frames 3 $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) :
+ $(18) : $(19) ;
 }
 
 
@@ -180,7 +191,9 @@
 #
 rule warning
 {
- backtrace 2 warning: $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ backtrace 2 warning: $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) :
+ $(18) : $(19) ;
 }
 
 
@@ -192,7 +205,7 @@
 rule lol->list ( * )
 {
     local result ;
- local remaining = 1 2 3 4 5 6 7 8 9 ;
+ local remaining = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;
     while $($(remaining))
     {
         local n = $(remaining[1]) ;
@@ -219,7 +232,7 @@
     while $(bt) && ! $(result)
     {
         local m = [ MATCH ^(.+)\\.$ : $(bt[3]) ] ;
- local user-modules = ([Jj]amroot(.jam|.v2|)|([Jj]amfile(.jam|.v2|)|user-config.jam|site-config.jam|project-root.jam) ;
+ local user-modules = ([Jj]amroot(.jam|.v2|)|([Jj]amfile(.jam|.v2|)|user-config.jam|site-config.jam|project-config.jam|project-root.jam) ;
 
         if [ MATCH $(user-modules) : $(bt[1]:D=) ]
         {

Modified: branches/release/tools/build/v2/kernel/modules.jam
==============================================================================
--- branches/release/tools/build/v2/kernel/modules.jam (original)
+++ branches/release/tools/build/v2/kernel/modules.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,7 +1,8 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2003, 2005 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Essentially an include guard; ensures that no module is loaded multiple times.
 .loaded ?= ;
@@ -46,7 +47,8 @@
             }
 
             local test-module = __test-$(m)__ ;
- IMPORT $(m) : [ RULENAMES $(m) ] : $(test-module) : [ RULENAMES $(m) ] ;
+ IMPORT $(m) : [ RULENAMES $(m) ] : $(test-module) : [ RULENAMES $(m)
+ ] ;
             IMPORT $(m) : __test__ : $(test-module) : __test__ : LOCALIZE ;
             module $(test-module)
             {
@@ -94,13 +96,15 @@
 # Call the given rule locally in the given module. Use this for rules accepting
 # rule names as arguments, so that the passed rule may be invoked in the context
 # of the rule's caller (for example, if the rule accesses module globals or is a
-# local rule). Note that rules called this way may accept at most 8 parameters.
+# local rule). Note that rules called this way may accept at most 18 parameters.
 #
 rule call-in ( module-name ? : rule-name args * : * )
 {
     module $(module-name)
     {
- return [ $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
+ return [ $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) :
+ $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) : $(18) :
+ $(19) ] ;
     }
 }
 
@@ -108,18 +112,19 @@
 # Given a possibly qualified rule name and arguments, remove any initial module
 # qualification from the rule and invoke it in that module. If there is no
 # module qualification, the rule is invoked in the global module. Note that
-# rules called this way may accept at most 8 parameters.
+# rules called this way may accept at most 18 parameters.
 #
 rule call-locally ( qualified-rule-name args * : * )
 {
     local module-rule = [ MATCH (.*)\\.(.*) : $(qualified-rule-name) ] ;
     local rule-name = $(module-rule[2]) ;
     rule-name ?= $(qualified-rule-name) ;
- # We pass only 8 parameters here since Boost Jam allows at most 9 rule
+ # We pass only 18 parameters here since Boost Jam allows at most 19 rule
     # parameter positions and the call-in rule already uses up the initial
     # position for the module name.
     return [ call-in $(module-rule[1]) : $(rule-name) $(args) : $(2) : $(3) :
- $(4) : $(5) : $(6) : $(7) : $(8) ] ;
+ $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13)
+ $(14) : $(15) : $(16) : $(17) : $(18) : $(19) ] ;
 }
 
 
@@ -260,8 +265,8 @@
     {
         if ! $(m) in $(.loaded)
         {
- # If the importing module isn't already in the BOOST_BUILD_PATH,
- # prepend it to the path. We don't want to invert the search order
+ # If the importing module is not already in the BOOST_BUILD_PATH,
+ # prepend it to the path. We do not want to invert the search order
             # of modules that are already there.
 
             local caller-location ;
@@ -269,7 +274,8 @@
             {
                 caller-location = [ binding $(caller) ] ;
                 caller-location = $(caller-location:D) ;
- caller-location = [ normalize-raw-paths $(caller-location:R=$(.cwd)) ] ;
+ caller-location = [ normalize-raw-paths
+ $(caller-location:R=$(.cwd)) ] ;
             }
 
             local search = [ peek : BOOST_BUILD_PATH ] ;
@@ -312,11 +318,10 @@
 #
 rule clone-rules ( source-module target-module )
 {
- local rules = [ RULENAMES $(source-module) ] ;
-
- IMPORT $(source-module) : $(rules) : $(target-module) : $(rules) : LOCALIZE ;
- EXPORT $(target-module) : $(rules) ;
- IMPORT $(target-module) : $(rules) : : $(target-module).$(rules) ;
+ local r = [ RULENAMES $(source-module) ] ;
+ IMPORT $(source-module) : $(r) : $(target-module) : $(r) : LOCALIZE ;
+ EXPORT $(target-module) : $(r) ;
+ IMPORT $(target-module) : $(r) : : $(target-module).$(r) ;
 }
 
 

Modified: branches/release/tools/build/v2/notes/README.txt
==============================================================================
--- branches/release/tools/build/v2/notes/README.txt (original)
+++ branches/release/tools/build/v2/notes/README.txt 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,8 +1,8 @@
-Copyright 2005 Vladimir Prus
-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)
+Copyright 2005 Vladimir Prus
+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)
 
 
 This directory contains various development notes. Some of them
 may eventually find the way into documentation, so are purely
-imlementation comments.
+implementation comments.

Modified: branches/release/tools/build/v2/roll.sh
==============================================================================
--- branches/release/tools/build/v2/roll.sh (original)
+++ branches/release/tools/build/v2/roll.sh 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,10 +1,11 @@
 #!/bin/bash
 
 # Copyright 2004 Aleksey Gurtovoy
-# Copyright 2006 Rene Rivera
-# Copyright 2003, 2004, 2005, 2006 Vladimir Prus
-# 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)
+# Copyright 2006 Rene Rivera
+# Copyright 2003, 2004, 2005, 2006 Vladimir Prus
+# 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)
 
 set -e
 
@@ -13,9 +14,6 @@
 echo "SVN Revision $revision" >> timestamp.txt
 date >> timestamp.txt
 
-# This one is not fully finished
-rm -rf example/versioned
-
 # Remove unnecessary top-level files
 find . -maxdepth 1 -type f | egrep -v "boost-build.jam|timestamp.txt|roll.sh|bootstrap.jam|build-system.jam|boost_build.png|index.html|hacking.txt|site-config.jam|user-config.jam|bootstrap.sh|bootstrap.bat|Jamroot.jam" | xargs rm -f
 

Modified: branches/release/tools/build/v2/test/BoostBuild.py
==============================================================================
--- branches/release/tools/build/v2/test/BoostBuild.py (original)
+++ branches/release/tools/build/v2/test/BoostBuild.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,19 +2,21 @@
 # Copyright 2002-2003 Dave Abrahams.
 # Copyright 2006 Rene Rivera.
 # 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 accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import TestCmd
+
 import copy
 import fnmatch
 import glob
 import math
 import os
+import os.path
 import re
 import shutil
-import string
 import StringIO
+import subprocess
 import sys
 import tempfile
 import time
@@ -25,13 +27,16 @@
 from xml.sax.saxutils import escape
 
 
+class TestEnvironmentError(Exception):
+ pass
+
+
 annotations = []
 
 
 def print_annotation(name, value, xml):
- """Writes some named bits of information about test run.
- """
- if xml:
+ """Writes some named bits of information about the current test run."""
+ if xml:
         print escape(name) + " {{{"
         print escape(value)
         print "}}}"
@@ -39,93 +44,110 @@
         print name + " {{{"
         print value
         print "}}}"
-
+
+
 def flush_annotations(xml=0):
     global annotations
     for ann in annotations:
         print_annotation(ann[0], ann[1], xml)
     annotations = []
 
+
 def clear_annotations():
     global annotations
     annotations = []
 
-defer_annotations = 0
 
+defer_annotations = 0
 
 def set_defer_annotations(n):
     global defer_annotations
     defer_annotations = n
 
 
+def annotate_stack_trace(tb=None):
+ if tb:
+ trace = TestCmd.caller(traceback.extract_tb(tb), 0)
+ else:
+ trace = TestCmd.caller(traceback.extract_stack(), 1)
+ annotation("stacktrace", trace)
+
+
 def annotation(name, value):
- """Records an annotation about the test run.
- """
+ """Records an annotation about the test run."""
     annotations.append((name, value))
     if not defer_annotations:
         flush_annotations()
 
 
 def get_toolset():
- toolset = None;
+ toolset = None
     for arg in sys.argv[1:]:
- if not arg.startswith('-'):
+ if not arg.startswith("-"):
             toolset = arg
- return toolset or 'gcc'
+ return toolset or "gcc"
 
 
 # Detect the host OS.
-windows = False
-cygwin = False
-if os.environ.get('OS', '').lower().startswith('windows'):
- windows = True
+cygwin = hasattr(os, "uname") and os.uname()[0].lower().startswith("cygwin")
+windows = cygwin or os.environ.get("OS", "").lower().startswith("windows")
 
-if os.__dict__.has_key('uname') and \
- os.uname()[0].lower().startswith('cygwin'):
- windows = True
- cygwin = True
 
-suffixes = {}
+def prepare_prefixes_and_suffixes(toolset):
+ prepare_suffix_map(toolset)
+ prepare_library_prefix(toolset)
 
 
-# Configuration stating whether Boost Build is expected to automatically prepend
-# prefixes to built library targets.
-lib_prefix = "lib"
-dll_prefix = "lib"
-
-# Prepare the map of suffixes
 def prepare_suffix_map(toolset):
- global windows
+ """
+ Set up suffix translation performed by the Boost Build testing framework
+ to accomodate different toolsets generating targets of the same type using
+ different filename extensions (suffixes).
+
+ """
     global suffixes
- global cygwin
- global lib_prefix
- global dll_prefix
- suffixes = {'.exe': '', '.dll': '.so', '.lib': '.a', '.obj': '.o'}
- suffixes['.implib'] = '.no_implib_files_on_this_platform'
+ suffixes = {}
     if windows:
- suffixes = {}
- if toolset in ["gcc"]:
- suffixes['.lib'] = '.a' # static libs have '.a' suffix with mingw...
- suffixes['.obj'] = '.o'
+ if toolset == "gcc":
+ suffixes[".lib"] = ".a" # mingw static libs use suffix ".a".
+ suffixes[".obj"] = ".o"
         if cygwin:
- suffixes['.implib'] = '.lib.a'
+ suffixes[".implib"] = ".lib.a"
         else:
- suffixes['.implib'] = '.lib'
- if os.__dict__.has_key('uname') and (os.uname()[0] == 'Darwin'):
- suffixes['.dll'] = '.dylib'
-
+ suffixes[".implib"] = ".lib"
+ else:
+ suffixes[".exe"] = ""
+ suffixes[".dll"] = ".so"
+ suffixes[".lib"] = ".a"
+ suffixes[".obj"] = ".o"
+ suffixes[".implib"] = ".no_implib_files_on_this_platform"
+
+ if hasattr(os, "uname") and os.uname()[0] == "Darwin":
+ suffixes[".dll"] = ".dylib"
+
+
+def prepare_library_prefix(toolset):
+ """
+ Setup whether Boost Build is expected to automatically prepend prefixes
+ to its built library targets.
+
+ """
+ global lib_prefix
     lib_prefix = "lib"
- dll_prefix = "lib"
+
+ global dll_prefix
     if cygwin:
         dll_prefix = "cyg"
- elif windows and not toolset in ["gcc"]:
+ elif windows and toolset != "gcc":
         dll_prefix = None
+ else:
+ dll_prefix = "lib"
 
 
 def re_remove(sequence, regex):
     me = re.compile(regex)
     result = filter(lambda x: me.match(x), sequence)
- if 0 == len(result):
+ if not result:
         raise ValueError()
     for r in result:
         sequence.remove(r)
@@ -133,34 +155,12 @@
 
 def glob_remove(sequence, pattern):
     result = fnmatch.filter(sequence, pattern)
- if 0 == len(result):
+ if not result:
         raise ValueError()
     for r in result:
         sequence.remove(r)
 
 
-
-#
-# FIXME: this is copy-pasted from TestSCons.py
-# Should be moved to TestCmd.py?
-#
-if os.name == 'posix':
- def _failed(self, status=0):
- if self.status is None:
- return None
- return _status(self) != status
- def _status(self):
- if os.WIFEXITED(self.status):
- return os.WEXITSTATUS(self.status)
- else:
- return -1
-elif os.name == 'nt':
- def _failed(self, status=0):
- return not self.status is None and self.status != status
- def _status(self):
- return self.status
-
-
 class Tester(TestCmd.TestCmd):
     """Main tester class for Boost Build.
 
@@ -177,7 +177,7 @@
                                     match those actually created by the current
                                     toolset. For example, static library files
                                     are specified by using the .lib suffix but
- when the 'gcc' toolset is used it actually
+ when the "gcc" toolset is used it actually
                                     creates them using the .a suffix.
     `pass_toolset` - Whether the test system should pass the
                                     specified toolset to the run executable.
@@ -186,34 +186,39 @@
                                     configuration file.
     `ignore_toolset_requirements` - Whether the test system should tell the run
                                     executable to ignore toolset requirements.
- `workdir` - indicates an absolute directory where the
- test will be run from.
+ `workdir` - Absolute directory where the test will be
+ run from.
+ `pass_d0` - If set, when tests are not explicitly run
+ in verbose mode, they are run as silent
+ (-d0 & --quiet Boost Jam options).
 
     Optional arguments inherited from the base class:
 
- `description` - Test description string displayed in case of
- a failed test.
- `subdir' - List of subdirectories to automatically
+ `description` - Test description string displayed in case
+ of a failed test.
+ `subdir` - List of subdirectories to automatically
                                     create under the working directory. Each
                                     subdirectory needs to be specified
- separately parent coming before its child.
- `verbose` - Flag that may be used to enable more verbose
- test system output. Note that it does not
- also enable more verbose build system
- output like the --verbose command line
- option does.
+ separately, parent coming before its child.
+ `verbose` - Flag that may be used to enable more
+ verbose test system output. Note that it
+ does not also enable more verbose build
+ system output like the --verbose command
+ line option does.
     """
- def __init__(self, arguments="", executable="bjam",
+ def __init__(self, arguments=None, executable="bjam",
         match=TestCmd.match_exact, boost_build_path=None,
         translate_suffixes=True, pass_toolset=True, use_test_config=True,
- ignore_toolset_requirements=True, workdir="", pass_d0=True, **keywords):
+ ignore_toolset_requirements=True, workdir="", pass_d0=True,
+ **keywords):
 
+ assert arguments.__class__ is not str
         self.original_workdir = os.getcwd()
- if workdir != '' and not os.path.isabs(workdir):
- raise "Parameter workdir <"+workdir+"> must point to an absolute directory: "
+ if workdir and not os.path.isabs(workdir):
+ raise ("Parameter workdir <%s> must point to an absolute "
+ "directory: " % workdir)
 
- self.last_build_time_start = 0
- self.last_build_time_finish = 0
+ self.last_build_timestamp = 0
         self.translate_suffixes = translate_suffixes
         self.use_test_config = use_test_config
 
@@ -221,28 +226,32 @@
         self.pass_toolset = pass_toolset
         self.ignore_toolset_requirements = ignore_toolset_requirements
 
- prepare_suffix_map(pass_toolset and self.toolset or 'gcc')
+ prepare_prefixes_and_suffixes(pass_toolset and self.toolset or "gcc")
+
+ use_default_bjam = "--default-bjam" in sys.argv
 
- if not '--default-bjam' in sys.argv:
+ if not use_default_bjam:
             jam_build_dir = ""
- if os.name == 'nt':
+ if os.name == "nt":
                 jam_build_dir = "bin.ntx86"
- elif (os.name == 'posix') and os.__dict__.has_key('uname'):
- if os.uname()[0].lower().startswith('cygwin'):
+ elif (os.name == "posix") and os.__dict__.has_key("uname"):
+ if os.uname()[0].lower().startswith("cygwin"):
                     jam_build_dir = "bin.cygwinx86"
- if 'TMP' in os.environ and os.environ['TMP'].find('~') != -1:
- print 'Setting $TMP to /tmp to get around problem with short path names'
- os.environ['TMP'] = '/tmp'
- elif os.uname()[0] == 'Linux':
+ if ("TMP" in os.environ and
+ os.environ["TMP"].find("~") != -1):
+ print("Setting $TMP to /tmp to get around problem "
+ "with short path names")
+ os.environ["TMP"] = "/tmp"
+ elif os.uname()[0] == "Linux":
                     cpu = os.uname()[4]
                     if re.match("i.86", cpu):
- jam_build_dir = "bin.linuxx86";
+ jam_build_dir = "bin.linuxx86"
                     else:
                         jam_build_dir = "bin.linux" + os.uname()[4]
- elif os.uname()[0] == 'SunOS':
+ elif os.uname()[0] == "SunOS":
                     jam_build_dir = "bin.solaris"
- elif os.uname()[0] == 'Darwin':
- if os.uname()[4] == 'i386':
+ elif os.uname()[0] == "Darwin":
+ if os.uname()[4] == "i386":
                         jam_build_dir = "bin.macosxx86"
                     else:
                         jam_build_dir = "bin.macosxppc"
@@ -255,54 +264,47 @@
                 elif os.uname()[0] == "OSF1":
                     jam_build_dir = "bin.osf"
                 else:
- raise "Don't know directory where Jam is built for this system: " + os.name + "/" + os.uname()[0]
+ raise ("Do not know directory where Jam is built for this "
+ "system: %s/%s" % (os.name, os.uname()[0]))
             else:
- raise "Don't know directory where Jam is built for this system: " + os.name
+ raise ("Do not know directory where Jam is built for this "
+ "system: %s" % os.name)
 
             # Find where jam_src is located. Try for the debug version if it is
             # lying around.
- dirs = [os.path.join('../engine', jam_build_dir + '.debug'),
- os.path.join('../engine', jam_build_dir),
- ]
+ dirs = [os.path.join("..", "engine", jam_build_dir + ".debug"),
+ os.path.join("..", "engine", jam_build_dir)]
             for d in dirs:
                 if os.path.exists(d):
                     jam_build_dir = d
                     break
             else:
- print "Cannot find built Boost.Jam"
+ print("Cannot find built Boost.Jam")
                 sys.exit(1)
 
- verbosity = ['-d0', '--quiet']
+ verbosity = ["-d0", "--quiet"]
         if not pass_d0:
             verbosity = []
- if '--verbose' in sys.argv:
- keywords['verbose'] = True
- verbosity = ['-d+2']
+ if "--verbose" in sys.argv:
+ keywords["verbose"] = True
+ verbosity = ["-d+2"]
 
         if boost_build_path is None:
             boost_build_path = self.original_workdir + "/.."
 
         program_list = []
-
- if '--default-bjam' in sys.argv:
+ if use_default_bjam:
             program_list.append(executable)
- inpath_bjam = True
         else:
             program_list.append(os.path.join(jam_build_dir, executable))
- inpath_bjam = None
         program_list.append('-sBOOST_BUILD_PATH="' + boost_build_path + '"')
         if verbosity:
             program_list += verbosity
         if arguments:
- program_list += arguments.split(" ")
+ program_list += arguments
 
- TestCmd.TestCmd.__init__(
- self
- , program=program_list
- , match=match
- , workdir=workdir
- , inpath=inpath_bjam
- , **keywords)
+ TestCmd.TestCmd.__init__(self, program=program_list, match=match,
+ workdir=workdir, inpath=use_default_bjam, **keywords)
 
         os.chdir(self.workdir)
 
@@ -330,39 +332,23 @@
         shutil.copytree(tree_location, self.workdir)
 
         os.chdir(d)
-
         def make_writable(unused, dir, entries):
             for e in entries:
                 name = os.path.join(dir, e)
- os.chmod(name, os.stat(name)[0] | 0222)
-
+ os.chmod(name, os.stat(name).st_mode | 0222)
         os.path.walk(".", make_writable, None)
 
- def write(self, file, content):
- self.wait_for_time_change_since_last_build()
+ def write(self, file, content, wait=True):
         nfile = self.native_file_name(file)
+ self.__makedirs(os.path.dirname(nfile), wait)
+ f = open(nfile, "wb")
         try:
- os.makedirs(os.path.dirname(nfile))
- except Exception, e:
- pass
- open(nfile, "wb").write(content)
-
- def rename(self, old, new):
- try:
- os.makedirs(os.path.dirname(new))
- except:
- pass
-
- try:
- os.remove(new)
- except:
- pass
-
- os.rename(old, new)
- self.touch(new);
+ f.write(content)
+ finally:
+ f.close()
+ self.__ensure_newer_than_last_build(nfile)
 
     def copy(self, src, dst):
- self.wait_for_time_change_since_last_build()
         try:
             self.write(dst, self.read(src, 1))
         except:
@@ -375,31 +361,33 @@
         self.write(dst, self.read(src, 1))
         os.utime(dst_name, (stats.st_atime, stats.st_mtime))
 
- def touch(self, names):
- self.wait_for_time_change_since_last_build()
- for name in self.adjust_names(names):
- os.utime(self.native_file_name(name), None)
+ def touch(self, names, wait=True):
+ if names.__class__ is str:
+ names = [names]
+ for name in names:
+ path = self.native_file_name(name)
+ if wait:
+ self.__ensure_newer_than_last_build(path)
+ else:
+ os.utime(path, None)
 
     def rm(self, names):
         if not type(names) == types.ListType:
             names = [names]
-
- if names == ["."]:
- # If we're deleting the entire workspace, there's no
- # need to wait for a clock tick.
- self.last_build_time_start = 0
- self.last_build_time_finish = 0
 
- self.wait_for_time_change_since_last_build()
+ if names == ["."]:
+ # If we are deleting the entire workspace, there is no need to wait
+ # for a clock tick.
+ self.last_build_timestamp = 0
 
         # Avoid attempts to remove the current directory.
         os.chdir(self.original_workdir)
         for name in names:
- n = self.native_file_name(name)
- n = glob.glob(n)
+ n = glob.glob(self.native_file_name(name))
             if n: n = n[0]
             if not n:
- n = self.glob_file(string.replace(name, "$toolset", self.toolset+"*"))
+ n = self.glob_file(name.replace("$toolset", self.toolset + "*")
+ )
             if n:
                 if os.path.isdir(n):
                     shutil.rmtree(n, ignore_errors=False)
@@ -412,81 +400,91 @@
         os.chdir(self.workdir)
 
     def expand_toolset(self, name):
- """Expands $toolset in the given file to tested toolset.
         """
- content = self.read(name)
- content = string.replace(content, "$toolset", self.toolset)
- self.write(name, content)
+ Expands $toolset placeholder in the given file to the name of the
+ toolset currently being tested.
+
+ """
+ self.write(name, self.read(name).replace("$toolset", self.toolset))
 
     def dump_stdio(self):
         annotation("STDOUT", self.stdout())
         annotation("STDERR", self.stderr())
 
- #
- # FIXME: Large portion copied from TestSCons.py, should be moved?
- #
- def run_build_system(self, extra_args="", subdir="", stdout=None, stderr="",
- status=0, match=None, pass_toolset=None, use_test_config=None,
- ignore_toolset_requirements=None, expected_duration=None, **kw):
+ def run_build_system(self, extra_args=None, subdir="", stdout=None,
+ stderr="", status=0, match=None, pass_toolset=None,
+ use_test_config=None, ignore_toolset_requirements=None,
+ expected_duration=None, **kw):
+
+ assert extra_args.__class__ is not str
+
+ if os.path.isabs(subdir):
+ print("You must pass a relative directory to subdir <%s>." % subdir
+ )
+ return
 
- self.last_build_time_start = time.time()
+ self.previous_tree, dummy = tree.build_tree(self.workdir)
 
- try:
- if os.path.isabs(subdir):
- if stderr:
- print "You must pass a relative directory to subdir <"+subdir+">."
- status = 1
- return
+ if match is None:
+ match = self.match
 
- self.previous_tree = tree.build_tree(self.workdir)
+ if pass_toolset is None:
+ pass_toolset = self.pass_toolset
 
- if match is None:
- match = self.match
+ if use_test_config is None:
+ use_test_config = self.use_test_config
 
- if pass_toolset is None:
- pass_toolset = self.pass_toolset
+ if ignore_toolset_requirements is None:
+ ignore_toolset_requirements = self.ignore_toolset_requirements
 
- if use_test_config is None:
- use_test_config = self.use_test_config
+ try:
+ kw["program"] = []
+ kw["program"] += self.program
+ if extra_args:
+ kw["program"] += extra_args
+ if pass_toolset:
+ kw["program"].append("toolset=" + self.toolset)
+ if use_test_config:
+ kw["program"].append('--test-config="%s"' % os.path.join(
+ self.original_workdir, "test-config.jam"))
+ if ignore_toolset_requirements:
+ kw["program"].append("--ignore-toolset-requirements")
+ if "--python" in sys.argv:
+ kw["program"].append("--python")
+ kw["chdir"] = subdir
+ self.last_program_invocation = kw["program"]
+ build_time_start = time.time()
+ apply(TestCmd.TestCmd.run, [self], kw)
+ build_time_finish = time.time()
+ except:
+ self.dump_stdio()
+ raise
 
- if ignore_toolset_requirements is None:
- ignore_toolset_requirements = self.ignore_toolset_requirements
+ old_last_build_timestamp = self.last_build_timestamp
+ self.tree, self.last_build_timestamp = tree.build_tree(self.workdir)
+ self.difference = tree.tree_difference(self.previous_tree, self.tree)
+ if self.difference.empty():
+ # If nothing has been changed by this build and sufficient time has
+ # passed since the last build that actually changed something,
+ # there is no need to wait for touched or newly created files to
+ # start getting newer timestamps than the currently existing ones.
+ self.last_build_timestamp = old_last_build_timestamp
 
- try:
- kw['program'] = []
- kw['program'] += self.program
- if extra_args:
- kw['program'] += extra_args.split(" ")
- if pass_toolset:
- kw['program'].append("toolset=" + self.toolset)
- if use_test_config:
- kw['program'].append('--test-config="%s"'
- % os.path.join(self.original_workdir, "test-config.jam"))
- if ignore_toolset_requirements:
- kw['program'].append("--ignore-toolset-requirements")
- if "--python" in sys.argv:
- kw['program'].append("--python")
- kw['chdir'] = subdir
- self.last_program_invocation = kw['program']
- apply(TestCmd.TestCmd.run, [self], kw)
- except:
- self.dump_stdio()
- raise
- finally:
- self.last_build_time_finish = time.time()
+ self.difference.ignore_directories()
+ self.unexpected_difference = copy.deepcopy(self.difference)
 
- if (status != None) and _failed(self, status):
- expect = ''
+ if (status and self.status) is not None and self.status != status:
+ expect = ""
             if status != 0:
                 expect = " (expected %d)" % status
 
- annotation("failure", '"%s" returned %d%s'
- % (kw['program'], _status(self), expect))
-
+ annotation("failure", '"%s" returned %d%s' % (kw["program"],
+ self.status, expect))
+
             annotation("reason", "unexpected status returned by bjam")
             self.fail_test(1)
 
- if not (stdout is None) and not match(self.stdout(), stdout):
+ if stdout is not None and not match(self.stdout(), stdout):
             annotation("failure", "Unexpected stdout")
             annotation("Expected STDOUT", stdout)
             annotation("Actual STDOUT", self.stdout())
@@ -500,7 +498,7 @@
         intel_workaround = re.compile("^xi(link|lib): executing.*\n", re.M)
         actual_stderr = re.sub(intel_workaround, "", self.stderr())
 
- if not (stderr is None) and not match(actual_stderr, stderr):
+ if stderr is not None and not match(actual_stderr, stderr):
             annotation("failure", "Unexpected stderr")
             annotation("Expected STDERR", stderr)
             annotation("Actual STDERR", self.stderr())
@@ -508,27 +506,20 @@
             self.maybe_do_diff(actual_stderr, stderr)
             self.fail_test(1, dump_stdio=False)
 
- if not expected_duration is None:
- actual_duration = self.last_build_time_finish - self.last_build_time_start
- if (actual_duration > expected_duration):
- print "Test run lasted %f seconds while it was expected to " \
+ if expected_duration is not None:
+ actual_duration = build_time_finish - build_time_start
+ if actual_duration > expected_duration:
+ print("Test run lasted %f seconds while it was expected to "
                     "finish in under %f seconds." % (actual_duration,
- expected_duration)
+ expected_duration))
                 self.fail_test(1, dump_stdio=False)
 
- self.tree = tree.build_tree(self.workdir)
- self.difference = tree.trees_difference(self.previous_tree, self.tree)
- if self.difference.empty():
- # If nothing was changed, there's no need to wait
- self.last_build_time_start = 0
- self.last_build_time_finish = 0
- self.difference.ignore_directories()
- self.unexpected_difference = copy.deepcopy(self.difference)
-
     def glob_file(self, name):
         result = None
- if hasattr(self, 'difference'):
- for f in self.difference.added_files+self.difference.modified_files+self.difference.touched_files:
+ if hasattr(self, "difference"):
+ for f in (self.difference.added_files +
+ self.difference.modified_files +
+ self.difference.touched_files):
                 if fnmatch.fnmatch(f, name):
                     result = self.native_file_name(f)
                     break
@@ -541,43 +532,48 @@
     def read(self, name, binary=False):
         try:
             if self.toolset:
- name = string.replace(name, "$toolset", self.toolset+"*")
+ name = name.replace("$toolset", self.toolset + "*")
             name = self.glob_file(name)
             openMode = "r"
             if binary:
                 openMode += "b"
             else:
                 openMode += "U"
- return open(name, openMode).read()
+ f = open(name, openMode)
+ result = f.read()
+ f.close()
+ return result
         except:
             annotation("failure", "Could not open '%s'" % name)
             self.fail_test(1)
- return ''
+ return ""
 
     def read_and_strip(self, name):
         if not self.glob_file(name):
- return ''
+ return ""
         f = open(self.glob_file(name), "rb")
         lines = f.readlines()
- result = string.join(map(string.rstrip, lines), "\n")
- if lines and lines[-1][-1] == '\n':
- return result + '\n'
- else:
- return result
+ f.close()
+ result = "\n".join(x.rstrip() for x in lines)
+ if lines and lines[-1][-1] != "\n":
+ return result + "\n"
+ return result
 
- def fail_test(self, condition, dump_stdio=True, *args):
+ def fail_test(self, condition, dump_difference=True, dump_stdio=True,
+ dump_stack=True):
         if not condition:
             return
 
- if hasattr(self, 'difference'):
+ if dump_difference and hasattr(self, "difference"):
             f = StringIO.StringIO()
             self.difference.pprint(f)
- annotation("changes caused by the last build command", f.getvalue())
+ annotation("changes caused by the last build command",
+ f.getvalue())
 
         if dump_stdio:
             self.dump_stdio()
 
- if '--preserve' in sys.argv:
+ if "--preserve" in sys.argv:
             print
             print "*** Copying the state of working dir into 'failed_test' ***"
             print
@@ -585,13 +581,13 @@
             if os.path.isdir(path):
                 shutil.rmtree(path, ignore_errors=False)
             elif os.path.exists(path):
- raise "Path " + path + " already exists and is not a directory";
+ raise "Path " + path + " already exists and is not a directory"
             shutil.copytree(self.workdir, path)
             print "The failed command was:"
- print ' '.join(self.last_program_invocation)
+ print " ".join(self.last_program_invocation)
 
- at = TestCmd.caller(traceback.extract_stack(), 0)
- annotation("stacktrace", at)
+ if dump_stack:
+ annotate_stack_trace()
         sys.exit(1)
 
     # A number of methods below check expectations with actual difference
@@ -599,7 +595,7 @@
     # methods require exact names to be passed. All the 'ignore*' methods allow
     # wildcards.
 
- # All names can be lists, which are taken to be directory components.
+ # All names can be either a string or a list of strings.
     def expect_addition(self, names):
         for name in self.adjust_names(names):
             try:
@@ -609,7 +605,8 @@
                 self.fail_test(1)
 
     def ignore_addition(self, wildcard):
- self.ignore_elements(self.unexpected_difference.added_files, wildcard)
+ self.__ignore_elements(self.unexpected_difference.added_files,
+ wildcard)
 
     def expect_removal(self, names):
         for name in self.adjust_names(names):
@@ -620,18 +617,20 @@
                 self.fail_test(1)
 
     def ignore_removal(self, wildcard):
- self.ignore_elements(self.unexpected_difference.removed_files, wildcard)
+ self.__ignore_elements(self.unexpected_difference.removed_files,
+ wildcard)
 
     def expect_modification(self, names):
         for name in self.adjust_names(names):
             try:
                 glob_remove(self.unexpected_difference.modified_files, name)
             except:
- annotation("failure", "File %s not modified as expected" % name)
+ annotation("failure", "File %s not modified as expected" %
+ name)
                 self.fail_test(1)
 
     def ignore_modification(self, wildcard):
- self.ignore_elements(self.unexpected_difference.modified_files, \
+ self.__ignore_elements(self.unexpected_difference.modified_files,
             wildcard)
 
     def expect_touch(self, names):
@@ -657,13 +656,14 @@
                 self.fail_test(1)
 
     def ignore_touch(self, wildcard):
- self.ignore_elements(self.unexpected_difference.touched_files, wildcard)
+ self.__ignore_elements(self.unexpected_difference.touched_files,
+ wildcard)
 
     def ignore(self, wildcard):
- self.ignore_elements(self.unexpected_difference.added_files, wildcard)
- self.ignore_elements(self.unexpected_difference.removed_files, wildcard)
- self.ignore_elements(self.unexpected_difference.modified_files, wildcard)
- self.ignore_elements(self.unexpected_difference.touched_files, wildcard)
+ self.ignore_addition(wildcard)
+ self.ignore_removal(wildcard)
+ self.ignore_modification(wildcard)
+ self.ignore_touch(wildcard)
 
     def expect_nothing(self, names):
         for name in self.adjust_names(names):
@@ -689,71 +689,40 @@
         # Not totally sure about this change, but I do not see a good
         # alternative.
         if windows:
- self.ignore('*.ilk') # MSVC incremental linking files.
- self.ignore('*.pdb') # MSVC program database files.
- self.ignore('*.rsp') # Response files.
- self.ignore('*.tds') # Borland debug symbols.
- self.ignore('*.manifest') # MSVC DLL manifests.
+ self.ignore("*.ilk") # MSVC incremental linking files.
+ self.ignore("*.pdb") # MSVC program database files.
+ self.ignore("*.rsp") # Response files.
+ self.ignore("*.tds") # Borland debug symbols.
+ self.ignore("*.manifest") # MSVC DLL manifests.
 
         # Debug builds of bjam built with gcc produce this profiling data.
- self.ignore('gmon.out')
- self.ignore('*/gmon.out')
+ self.ignore("gmon.out")
+ self.ignore("*/gmon.out")
 
+ # Boost Build's 'configure' functionality (unfinished at the time)
+ # produces this file.
         self.ignore("bin/config.log")
+ self.ignore("bin/project-cache.jam")
 
+ # Compiled Python files created when running Python based Boost Build.
         self.ignore("*.pyc")
 
         if not self.unexpected_difference.empty():
- annotation('failure', 'Unexpected changes found')
+ annotation("failure", "Unexpected changes found")
             output = StringIO.StringIO()
             self.unexpected_difference.pprint(output)
             annotation("unexpected changes", output.getvalue())
             self.fail_test(1)
 
- def __expect_line(self, content, expected, expected_to_exist):
- expected = expected.strip()
- lines = content.splitlines()
- found = False
- for line in lines:
- line = line.strip()
- if fnmatch.fnmatch(line, expected):
- found = True
- break
-
- if expected_to_exist and not found:
- annotation("failure",
- "Did not find expected line:\n%s\nin output:\n%s" %
- (expected, content))
- self.fail_test(1)
- if not expected_to_exist and found:
- annotation("failure",
- "Found an unexpected line:\n%s\nin output:\n%s" %
- (expected, content))
- self.fail_test(1)
-
- def expect_output_line(self, line, expected_to_exist=True):
- self.__expect_line(self.stdout(), line, expected_to_exist)
-
- def expect_content_line(self, name, line, expected_to_exist=True):
- content = self.__read_file(name)
- self.__expect_line(content, line, expected_to_exist)
+ def expect_output_lines(self, lines, expected=True):
+ self.__expect_lines(self.stdout(), lines, expected)
 
- def __read_file(self, name, exact=False):
- name = self.adjust_names(name)[0]
- result = ""
- try:
- if exact:
- result = self.read(name)
- else:
- result = string.replace(self.read_and_strip(name), "\\", "/")
- except (IOError, IndexError):
- print "Note: could not open file", name
- self.fail_test(1)
- return result
+ def expect_content_lines(self, filename, line, expected=True):
+ self.__expect_lines(self.__read_file(filename), line, expected)
 
     def expect_content(self, name, content, exact=False):
         actual = self.__read_file(name, exact)
- content = string.replace(content, "$toolset", self.toolset+"*")
+ content = content.replace("$toolset", self.toolset + "*")
 
         matched = False
         if exact:
@@ -782,50 +751,36 @@
             self.fail_test(1)
 
     def maybe_do_diff(self, actual, expected):
- if os.environ.has_key("DO_DIFF") and os.environ["DO_DIFF"] != '':
+ if os.environ.get("DO_DIFF"):
             e = tempfile.mktemp("expected")
             a = tempfile.mktemp("actual")
- open(e, "w").write(expected)
- open(a, "w").write(actual)
- print "DIFFERENCE"
- if os.system("diff -u " + e + " " + a):
- print "Unable to compute difference: diff -u %s %s" % (e, a)
+ f = open(e, "w")
+ f.write(expected)
+ f.close()
+ f = open(a, "w")
+ f.write(actual)
+ f.close()
+ print("DIFFERENCE")
+ # Current diff should return 1 to indicate 'different input files'
+ # but some older diff versions may return 0 and depending on the
+ # exact Python/OS platform version, os.system() call may gobble up
+ # the external process's return code and return 0 itself.
+ if os.system('diff -u "%s" "%s"' % (e, a)) not in [0, 1]:
+ print('Unable to compute difference: diff -u "%s" "%s"' % (e, a
+ ))
             os.unlink(e)
             os.unlink(a)
         else:
- print "Set environmental variable 'DO_DIFF' to examine difference."
-
- # Helpers.
- def mul(self, *arguments):
- if len(arguments) == 0:
- return None
-
- here = arguments[0]
- if type(here) == type(''):
- here = [here]
-
- if len(arguments) > 1:
- there = apply(self.mul, arguments[1:])
- result = []
- for i in here:
- for j in there:
- result.append(i + j)
- return result
-
- return here
+ print("Set environmental variable 'DO_DIFF' to examine the "
+ "difference.")
 
     # Internal methods.
- def ignore_elements(self, list, wildcard):
- """Removes in-place, element of 'list' that match the given wildcard.
- """
- list[:] = filter(lambda x, w=wildcard: not fnmatch.fnmatch(x, w), list)
-
     def adjust_lib_name(self, name):
         global lib_prefix
         global dll_prefix
         result = name
 
- pos = string.rfind(name, ".")
+ pos = name.rfind(".")
         if pos != -1:
             suffix = name[pos:]
             if suffix == ".lib":
@@ -838,70 +793,375 @@
                 if dll_prefix:
                     tail = dll_prefix + tail
                     result = os.path.join(head, tail)
- # If we want to use this name in a Jamfile, we better convert \ to /, as
- # otherwise we would have to quote \.
- result = string.replace(result, "\\", "/")
+ # If we want to use this name in a Jamfile, we better convert \ to /,
+ # as otherwise we would have to quote \.
+ result = result.replace("\\", "/")
         return result
 
     def adjust_suffix(self, name):
         if not self.translate_suffixes:
             return name
+ pos = name.rfind(".")
+ if pos == -1:
+ return name
+ suffix = name[pos:]
+ return name[:pos] + suffixes.get(suffix, suffix)
 
- pos = string.rfind(name, ".")
- if pos != -1:
- suffix = name[pos:]
- name = name[:pos]
-
- if suffixes.has_key(suffix):
- suffix = suffixes[suffix]
- else:
- suffix = ''
-
- return name + suffix
-
- # Acceps either a string or a list of strings and returns a list of strings.
- # Adjusts suffixes on all names.
+ # Acceps either a string or a list of strings and returns a list of
+ # strings. Adjusts suffixes on all names.
     def adjust_names(self, names):
- if type(names) == types.StringType:
+ if names.__class__ is str:
             names = [names]
         r = map(self.adjust_lib_name, names)
         r = map(self.adjust_suffix, r)
- r = map(lambda x, t=self.toolset: string.replace(x, "$toolset", t+"*"), r)
+ r = map(lambda x, t=self.toolset: x.replace("$toolset", t + "*"), r)
         return r
 
     def native_file_name(self, name):
         name = self.adjust_names(name)[0]
- elements = string.split(name, "/")
- return os.path.normpath(apply(os.path.join, [self.workdir]+elements))
+ return os.path.normpath(os.path.join(self.workdir, *name.split("/")))
+
+ def wait_for_time_change(self, path, touch):
+ """
+ Wait for newly assigned file system modification timestamps for the
+ given path to become large enough for the timestamp difference to be
+ correctly recognized by both this Python based testing framework and
+ the Boost Jam executable being tested. May optionally touch the given
+ path to set its modification timestamp to the new value.
+
+ """
+ self.__wait_for_time_change(path, touch, last_build_time=False)
 
- # Wait while time is no longer equal to the time last "run_build_system"
- # call finished. Used to avoid subsequent builds treating existing files as
- # 'current'.
- def wait_for_time_change_since_last_build(self):
- while 1:
- # In fact, I'm not sure why "+ 2" as opposed to "+ 1" is needed but
- # empirically, "+ 1" sometimes causes 'touch' and other functions
- # not to bump the file time enough for a rebuild to happen.
- if math.floor(time.time()) < math.floor(self.last_build_time_finish) + 2:
- time.sleep(0.1)
+ def __build_timestamp_resolution(self):
+ """
+ Returns the minimum path modification timestamp resolution supported
+ by the used Boost Jam executable.
+
+ """
+ dir = tempfile.mkdtemp("bjam_version_info")
+ try:
+ jam_script = "timestamp_resolution.jam"
+ f = open(os.path.join(dir, jam_script), "w")
+ try:
+ f.write("EXIT $(JAM_TIMESTAMP_RESOLUTION) : 0 ;")
+ finally:
+ f.close()
+ p = subprocess.Popen([self.program[0], "-d0", "-f%s" % jam_script],
+ stdout=subprocess.PIPE, cwd=dir, universal_newlines=True)
+ out, err = p.communicate()
+ finally:
+ shutil.rmtree(dir, ignore_errors=False)
+
+ if p.returncode != 0:
+ raise TestEnvironmentError("Unexpected return code (%s) when "
+ "detecting Boost Jam's minimum supported path modification "
+ "timestamp resolution version information." % p.returncode)
+ if err:
+ raise TestEnvironmentError("Unexpected error output (%s) when "
+ "detecting Boost Jam's minimum supported path modification "
+ "timestamp resolution version information." % err)
+
+ r = re.match("([0-9]{2}):([0-9]{2}):([0-9]{2}\\.[0-9]{9})$", out)
+ if not r:
+ # Older Boost Jam versions did not report their minimum supported
+ # path modification timestamp resolution and did not actually
+ # support path modification timestamp resolutions finer than 1
+ # second.
+ # TODO: Phase this support out to avoid such fallback code from
+ # possibly covering up other problems.
+ return 1
+ if r.group(1) != "00" or r.group(2) != "00": # hours, minutes
+ raise TestEnvironmentError("Boost Jam with too coarse minimum "
+ "supported path modification timestamp resolution (%s:%s:%s)."
+ % (r.group(1), r.group(2), r.group(3)))
+ return float(r.group(3)) # seconds.nanoseconds
+
+ def __ensure_newer_than_last_build(self, path):
+ """
+ Updates the given path's modification timestamp after waiting for the
+ newly assigned file system modification timestamp to become large
+ enough for the timestamp difference between it and the last build
+ timestamp to be correctly recognized by both this Python based testing
+ framework and the Boost Jam executable being tested. Does nothing if
+ there is no 'last build' information available.
+
+ """
+ if self.last_build_timestamp:
+ self.__wait_for_time_change(path, touch=True, last_build_time=True)
+
+ def __expect_lines(self, data, lines, expected):
+ """
+ Checks whether the given data contains the given lines.
+
+ Data may be specified as a single string containing text lines
+ separated by newline characters.
+
+ Lines may be specified in any of the following forms:
+ * Single string containing text lines separated by newlines - the
+ given lines are searched for in the given data without any extra
+ data lines between them.
+ * Container of strings containing text lines separated by newlines
+ - the given lines are searched for in the given data with extra
+ data lines allowed between lines belonging to different strings.
+ * Container of strings containing text lines separated by newlines
+ and containers containing strings - the same as above with the
+ internal containers containing strings being interpreted as if
+ all their content was joined together into a single string
+ separated by newlines.
+
+ A newline at the end of any multi-line lines string is interpreted as
+ an expected extra trailig empty line.
+ """
+ # str.splitlines() trims at most one trailing newline while we want the
+ # trailing newline to indicate that there should be an extra empty line
+ # at the end.
+ splitlines = lambda x : (x + "\n").splitlines()
+
+ if data is None:
+ data = []
+ elif data.__class__ is str:
+ data = splitlines(data)
+
+ if lines.__class__ is str:
+ lines = [splitlines(lines)]
+ else:
+ expanded = []
+ for x in lines:
+ if x.__class__ is str:
+ x = splitlines(x)
+ expanded.append(x)
+ lines = expanded
+
+ if _contains_lines(data, lines) != bool(expected):
+ output = []
+ if expected:
+ output = ["Did not find expected lines:"]
             else:
- break
+ output = ["Found unexpected lines:"]
+ first = True
+ for line_sequence in lines:
+ if line_sequence:
+ if first:
+ first = False
+ else:
+ output.append("...")
+ output.extend(" > " + line for line in line_sequence)
+ output.append("in output:")
+ output.extend(" > " + line for line in data)
+ annotation("failure", "\n".join(output))
+ self.fail_test(1)
 
+ def __ignore_elements(self, list, wildcard):
+ """Removes in-place 'list' elements matching the given 'wildcard'."""
+ list[:] = filter(lambda x, w=wildcard: not fnmatch.fnmatch(x, w), list)
 
-class List:
+ def __makedirs(self, path, wait):
+ """
+ Creates a folder with the given path, together with any missing
+ parent folders. If WAIT is set, makes sure any newly created folders
+ have modification timestamps newer than the ones left behind by the
+ last build run.
 
+ """
+ try:
+ if wait:
+ stack = []
+ while path and path not in stack and not os.path.isdir(path):
+ stack.append(path)
+ path = os.path.dirname(path)
+ while stack:
+ path = stack.pop()
+ os.mkdir(path)
+ self.__ensure_newer_than_last_build(path)
+ else:
+ os.makedirs(path)
+ except Exception:
+ pass
+
+ def __python_timestamp_resolution(self, path, minimum_resolution):
+ """
+ Returns the modification timestamp resolution for the given path
+ supported by the used Python interpreter/OS/filesystem combination.
+ Will not check for resolutions less than the given minimum value. Will
+ change the path's modification timestamp in the process.
+
+ Return values:
+ 0 - nanosecond resolution supported
+ positive decimal - timestamp resolution in seconds
+
+ """
+ # Note on Python's floating point timestamp support:
+ # Python interpreter versions prior to Python 2.3 did not support
+ # floating point timestamps. Versions 2.3 through 3.3 may or may not
+ # support it depending on the configuration (may be toggled by calling
+ # os.stat_float_times(True/False) at program startup, disabled by
+ # default prior to Python 2.5 and enabled by default since). Python 3.3
+ # deprecated this configuration and 3.4 removed support for it after
+ # which floating point timestamps are always supported.
+ ver = sys.version_info[0:2]
+ python_nanosecond_support = ver >= (3, 4) or (ver >= (2, 3) and
+ os.stat_float_times())
+
+ # Minimal expected floating point difference used to account for
+ # possible imprecise floating point number representations. We want
+ # this number to be small (at least smaller than 0.0001) but still
+ # large enough that we can be sure that increasing a floating point
+ # value by 2 * eta guarantees the value read back will be increased by
+ # at least eta.
+ eta = 0.00005
+
+ stats_orig = os.stat(path)
+ def test_time(diff):
+ """Returns whether a timestamp difference is detectable."""
+ os.utime(path, (stats_orig.st_atime, stats_orig.st_mtime + diff))
+ return os.stat(path).st_mtime > stats_orig.st_mtime + eta
+
+ # Test for nanosecond timestamp resolution support.
+ if not minimum_resolution and python_nanosecond_support:
+ if test_time(2 * eta):
+ return 0
+
+ # Detect the filesystem timestamp resolution. Note that there is no
+ # need to make this code 'as fast as possible' as, this function gets
+ # called before having to sleep until the next detectable modification
+ # timestamp value and that, since we already know nanosecond resolution
+ # is not supported, will surely take longer than whatever we do here to
+ # detect this minimal detectable modification timestamp resolution.
+ step = 0.1
+ if not python_nanosecond_support:
+ # If Python does not support nanosecond timestamp resolution we
+ # know the minimum possible supported timestamp resolution is 1
+ # second.
+ minimum_resolution = max(1, minimum_resolution)
+ index = max(1, int(minimum_resolution / step))
+ while step * index < minimum_resolution:
+ # Floating point number representation errors may cause our
+ # initially calculated start index to be too small if calculated
+ # directly.
+ index += 1
+ while True:
+ # Do not simply add up the steps to avoid cumulative floating point
+ # number representation errors.
+ next = step * index
+ if next > 10:
+ raise TestEnvironmentError("File systems with too coarse "
+ "modification timestamp resolutions not supported.")
+ if test_time(next):
+ return next
+ index += 1
+
+ def __read_file(self, name, exact=False):
+ name = self.adjust_names(name)[0]
+ result = ""
+ try:
+ if exact:
+ result = self.read(name)
+ else:
+ result = self.read_and_strip(name).replace("\\", "/")
+ except (IOError, IndexError):
+ print "Note: could not open file", name
+ self.fail_test(1)
+ return result
+
+ def __wait_for_time_change(self, path, touch, last_build_time):
+ """
+ Wait until a newly assigned file system modification timestamp for
+ the given path is large enough for the timestamp difference between it
+ and the last build timestamp or the path's original file system
+ modification timestamp (depending on the last_build_time flag) to be
+ correctly recognized by both this Python based testing framework and
+ the Boost Jam executable being tested. May optionally touch the given
+ path to set its modification timestamp to the new value.
+
+ """
+ assert self.last_build_timestamp or not last_build_time
+ stats_orig = os.stat(path)
+
+ if last_build_time:
+ start_time = self.last_build_timestamp
+ else:
+ start_time = stats_orig.st_mtime
+
+ build_resolution = self.__build_timestamp_resolution()
+ assert build_resolution >= 0
+
+ # Check whether the current timestamp is already new enough.
+ if stats_orig.st_mtime > start_time and (not build_resolution or
+ stats_orig.st_mtime >= start_time + build_resolution):
+ return
+
+ resolution = self.__python_timestamp_resolution(path, build_resolution)
+ assert resolution >= build_resolution
+
+ # Implementation notes:
+ # * Theoretically time.sleep() API might get interrupted too soon
+ # (never actually encountered).
+ # * We encountered cases where we sleep just long enough for the
+ # filesystem's modifiction timestamp to change to the desired value,
+ # but after waking up, the read timestamp is still just a tiny bit
+ # too small (encountered on Windows). This is most likely caused by
+ # imprecise floating point timestamp & sleep interval representation
+ # used by Python. Note though that we never encountered a case where
+ # more than one additional tiny sleep() call was needed to remedy
+ # the situation.
+ # * We try to wait long enough for the timestamp to change, but do not
+ # want to waste processing time by waiting too long. The main
+ # problem is that when we have a coarse resolution, the actual times
+ # get rounded and we do not know the exact sleep time needed for the
+ # difference between two such times to pass. E.g. if we have a 1
+ # second resolution and the original and the current file timestamps
+ # are both 10 seconds then it could be that the current time is
+ # 10.99 seconds and that we can wait for just one hundredth of a
+ # second for the current file timestamp to reach its next value, and
+ # using a longer sleep interval than that would just be wasting
+ # time.
+ while True:
+ os.utime(path, None)
+ c = os.stat(path).st_mtime
+ if resolution:
+ if c > start_time and (not build_resolution or c >= start_time
+ + build_resolution):
+ break
+ if c <= start_time - resolution:
+ # Move close to the desired timestamp in one sleep, but not
+ # close enough for timestamp rounding to potentially cause
+ # us to wait too long.
+ if start_time - c > 5:
+ if last_build_time:
+ error_message = ("Last build time recorded as "
+ "being a future event, causing a too long "
+ "wait period. Something must have played "
+ "around with the system clock.")
+ else:
+ error_message = ("Original path modification "
+ "timestamp set to far into the future or "
+ "something must have played around with the "
+ "system clock, causing a too long wait "
+ "period.\nPath: '%s'" % path)
+ raise TestEnvironmentError(message)
+ _sleep(start_time - c)
+ else:
+ # We are close to the desired timestamp so take baby sleeps
+ # to avoid sleeping too long.
+ _sleep(max(0.01, resolution / 10))
+ else:
+ if c > start_time:
+ break
+ _sleep(max(0.01, start_time - c))
+
+ if not touch:
+ os.utime(path, (stats_orig.st_atime, stats_orig.st_mtime))
+
+
+class List:
     def __init__(self, s=""):
         elements = []
- if isinstance(s, type("")):
- # Have to handle espaced spaces correctly.
- s = string.replace(s, "\ ", '\001')
- elements = string.split(s)
+ if s.__class__ is str:
+ # Have to handle escaped spaces correctly.
+ elements = s.replace("\ ", "\001").split()
         else:
- elements = s;
-
- self.l = []
- for e in elements:
- self.l.append(string.replace(e, '\001', ' '))
+ elements = s
+ self.l = [e.replace("\001", " ") for e in elements]
 
     def __len__(self):
         return len(self.l)
@@ -919,9 +1179,7 @@
         return str(self.l)
 
     def __repr__(self):
- return (self.__module__ + '.List('
- + repr(string.join(self.l, ' '))
- + ')')
+ return "%s.List(%r)" % (self.__module__, " ".join(self.l))
 
     def __mul__(self, other):
         result = List()
@@ -942,8 +1200,118 @@
         result.l = self.l[:] + other.l[:]
         return result
 
+
+def _contains_lines(data, lines):
+ data_line_count = len(data)
+ expected_line_count = reduce(lambda x, y: x + len(y), lines, 0)
+ index = 0
+ for expected in lines:
+ if expected_line_count > data_line_count - index:
+ return False
+ expected_line_count -= len(expected)
+ index = _match_line_sequence(data, index, data_line_count -
+ expected_line_count, expected)
+ if index < 0:
+ return False
+ return True
+
+
+def _match_line_sequence(data, start, end, lines):
+ if not lines:
+ return start
+ for index in xrange(start, end - len(lines) + 1):
+ data_index = index
+ for expected in lines:
+ if not fnmatch.fnmatch(data[data_index], expected):
+ break;
+ data_index += 1
+ else:
+ return data_index
+ return -1
+
+
+def _sleep(delay):
+ if delay > 5:
+ raise TestEnvironmentError("Test environment error: sleep period of "
+ "more than 5 seconds requested. Most likely caused by a file with "
+ "its modification timestamp set to sometime in the future.")
+ time.sleep(delay)
+
+
+###############################################################################
+#
+# Initialization.
+#
+###############################################################################
+
+# Make os.stat() return file modification times as floats instead of integers
+# to get the best possible file timestamp resolution available. The exact
+# resolution depends on the underlying file system and the Python os.stat()
+# implementation. The better the resolution we achieve, the shorter we need to
+# wait for files we create to start getting new timestamps.
+#
+# Additional notes:
+# * os.stat_float_times() function first introduced in Python 2.3. and
+# suggested for deprecation in Python 3.3.
+# * On Python versions 2.5+ we do not need to do this as there os.stat()
+# returns floating point file modification times by default.
+# * Windows CPython implementations prior to version 2.5 do not support file
+# modification timestamp resolutions of less than 1 second no matter whether
+# these timestamps are returned as integer or floating point values.
+# * Python documentation states that this should be set in a program's
+# __main__ module to avoid affecting other libraries that might not be ready
+# to support floating point timestamps. Since we use no such external
+# libraries, we ignore this warning to make it easier to enable this feature
+# in both our single & multiple-test scripts.
+if (2, 3) <= sys.version_info < (2, 5) and not os.stat_float_times():
+ os.stat_float_times(True)
+
+
 # Quickie tests. Should use doctest instead.
-if __name__ == '__main__':
+if __name__ == "__main__":
     assert str(List("foo bar") * "/baz") == "['foo/baz', 'bar/baz']"
     assert repr("foo/" * List("bar baz")) == "__main__.List('foo/bar foo/baz')"
- print 'tests passed'
+
+ assert _contains_lines([], [])
+ assert _contains_lines([], [[]])
+ assert _contains_lines([], [[], []])
+ assert _contains_lines([], [[], [], []])
+ assert not _contains_lines([], [[""]])
+ assert not _contains_lines([], [["a"]])
+
+ assert _contains_lines([""], [])
+ assert _contains_lines(["a"], [])
+ assert _contains_lines(["a", "b"], [])
+ assert _contains_lines(["a", "b"], [[], [], []])
+
+ assert _contains_lines([""], [[""]])
+ assert not _contains_lines([""], [["a"]])
+ assert not _contains_lines(["a"], [[""]])
+ assert _contains_lines(["a", "", "b", ""], [["a"]])
+ assert _contains_lines(["a", "", "b", ""], [[""]])
+ assert _contains_lines(["a", "", "b"], [["b"]])
+ assert not _contains_lines(["a", "b"], [[""]])
+ assert not _contains_lines(["a", "", "b", ""], [["c"]])
+ assert _contains_lines(["a", "", "b", "x"], [["x"]])
+
+ data = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
+ assert _contains_lines(data, [["1", "2"]])
+ assert not _contains_lines(data, [["2", "1"]])
+ assert not _contains_lines(data, [["1", "3"]])
+ assert not _contains_lines(data, [["1", "3"]])
+ assert _contains_lines(data, [["1"], ["2"]])
+ assert _contains_lines(data, [["1"], [], [], [], ["2"]])
+ assert _contains_lines(data, [["1"], ["3"]])
+ assert not _contains_lines(data, [["3"], ["1"]])
+ assert _contains_lines(data, [["3"], ["7"], ["8"]])
+ assert not _contains_lines(data, [["1"], ["3", "5"]])
+ assert not _contains_lines(data, [["1"], [""], ["5"]])
+ assert not _contains_lines(data, [["1"], ["5"], ["3"]])
+ assert not _contains_lines(data, [["1"], ["5", "3"]])
+
+ assert not _contains_lines(data, [[" 3"]])
+ assert not _contains_lines(data, [["3 "]])
+ assert not _contains_lines(data, [["3", ""]])
+ assert not _contains_lines(data, [["", "3"]])
+
+ print("tests passed")

Copied: branches/release/tools/build/v2/test/MockToolset.py (from r83773, /trunk/tools/build/v2/test/MockToolset.py)
==============================================================================
--- /trunk/tools/build/v2/test/MockToolset.py (original)
+++ branches/release/tools/build/v2/test/MockToolset.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -18,20 +18,25 @@
 parser.add_option('-x', dest="language")
 parser.add_option('-c', dest="compile", action="store_true")
 parser.add_option('-I', dest="includes", action="append")
+parser.add_option('-L', dest="library_path", action="append")
 parser.add_option('--dll', dest="dll", action="store_true")
 parser.add_option('--archive', dest="archive", action="store_true")
 parser.add_option('--static-lib', dest="static_libraries", action="append")
 parser.add_option('--shared-lib', dest="shared_libraries", action="append")
 
+cwd = os.environ["JAM_CWD"]
+
 class MockInfo(object):
- def __init__(self):
+ def __init__(self, verbose=False):
     self.files = dict()
     self.commands = list()
+ self.verbose = verbose
   def source_file(self, name, pattern):
     self.files[name] = pattern
   def action(self, command, status=0):
     self.commands.append((command, status))
   def check(self, command):
+ print "Testing command", command
     for (raw, status) in self.commands:
       if self.matches(raw, command):
         return status
@@ -39,7 +44,11 @@
     (expected_options, expected_args) = parser.parse_args(raw.split())
     options = command[0]
     input_files = list(command[1])
+ if self.verbose:
+ print " - matching against", (expected_options, expected_args)
     if len(expected_args) != len(input_files):
+ if self.verbose:
+ print " argument list sizes differ"
       return False
     for arg in expected_args:
       if arg.startswith('$'):
@@ -55,38 +64,72 @@
         if matching_file is not None:
           input_files.remove(matching_file)
         else:
+ if self.verbose:
+ print " Failed to match input file contents: %s" % arg
           return False
       else:
         if arg in input_files:
           input_files.remove(arg)
         else:
+ if self.verbose:
+ print " Failed to match input file: %s" % arg
           return False
 
     if options.language != expected_options.language:
+ if self.verbose:
+ print " Failed to match -c"
       return False
 
     if options.compile != expected_options.compile:
+ if self.verbose:
+ print " Failed to match -x"
       return False
 
+ # Normalize a path for comparison purposes
+ def adjust_path(p):
+ return os.path.normcase(os.path.normpath(os.path.join(cwd, p)))
+
     # order matters
     if options.includes is None:
       options.includes = []
     if expected_options.includes is None:
       expected_options.includes = []
- if map(os.path.abspath, options.includes) != \
- map(os.path.abspath, expected_options.includes):
+ if map(adjust_path, options.includes) != \
+ map(adjust_path, expected_options.includes):
+ if self.verbose:
+ print " Failed to match -I ", map(adjust_path, options.includes), \
+ " != ", map(adjust_path, expected_options.includes)
+ return False
+
+ if options.library_path is None:
+ options.library_path = []
+ if expected_options.library_path is None:
+ expected_options.library_path = []
+ if map(adjust_path, options.library_path) != \
+ map(adjust_path, expected_options.library_path):
+ if self.verbose:
+ print " Failed to match -L ", map(adjust_path, options.library_path), \
+ " != ", map(adjust_path, expected_options.library_path)
       return False
 
     if options.static_libraries != expected_options.static_libraries:
+ if self.verbose:
+ print " Failed to match --static-lib"
       return False
 
     if options.shared_libraries != expected_options.shared_libraries:
+ if self.verbose:
+ print " Failed to match --shared-lib"
       return False
 
     if options.dll != expected_options.dll:
+ if self.verbose:
+ print " Failed to match --dll"
       return False
 
     if options.archive != expected_options.archive:
+ if self.verbose:
+ print " Failed to match --archive"
       return False
 
     # The output must be handled after everything else
@@ -102,18 +145,18 @@
           with open(options.output_file, 'w') as output:
             output.write(fileid)
       else:
+ if self.verbose:
+ print "Failed to match -o"
         return False
     elif options.output_file is not None:
+ if self.verbose:
+ print "Failed to match -o"
       return False
 
     # if we've gotten here, then everything matched
+ if self.verbose:
+ print " Matched"
     return True
-
-_instance = MockInfo()
-
-def instance():
- return _instance
-
 ''')
 
   t.write('mock.py', '''
@@ -132,11 +175,23 @@
   t.write('mock.jam', '''
 import feature ;
 import toolset ;
-
-python-cmd = "\"%s\"" ;
+import path ;
+import modules ;
+import common ;
+import type ;
+
+.python-cmd = "\"%s\"" ;
+
+# Behave the same as gcc on Windows, because that's what
+# the test system expects
+type.set-generated-target-prefix SHARED_LIB : <toolset>mock <target-os>windows : lib ;
+type.set-generated-target-suffix STATIC_LIB : <toolset>mock <target-os>windows : a ;
 
 rule init ( )
 {
+ local here = [ path.make [ modules.binding $(__name__) ] ] ;
+ here = [ path.native [ path.root [ path.parent $(here) ] [ path.pwd ] ] ] ;
+ .config-cmd = [ common.variable-setting-command JAM_CWD : $(here) ] $(.python-cmd) -B ;
 }
 
 feature.extend toolset : mock ;
@@ -152,12 +207,12 @@
 
 actions compile.c
 {
- $(python-cmd) mock.py -c -x c -I$(INCLUDES) $(>) -o $(<)
+ $(.config-cmd) mock.py -c -x c -I"$(INCLUDES)" "$(>)" -o "$(<)"
 }
 
 actions compile.c++
 {
- $(python-cmd) mock.py -c -x c++ $(>) -o $(<)
+ $(.config-cmd) mock.py -c -x c++ -I"$(INCLUDES)" "$(>)" -o "$(<)"
 }
 
 toolset.flags mock.link USER_OPTIONS <linkflags> ;
@@ -168,27 +223,28 @@
 
 actions link
 {
- $(python-cmd) mock.py $(>) -o $(<) $(USER_OPTIONS) -L$(LINK_PATH) --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
+ $(.config-cmd) mock.py "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
 }
 
 actions archive
 {
- $(python-cmd) mock.py --archive $(>) -o $(<) $(USER_OPTIONS)
+ $(.config-cmd) mock.py --archive "$(>)" -o "$(<)" $(USER_OPTIONS)
 }
 
 actions link.dll
 {
- $(python-cmd) mock.py --dll $(>) -o $(<) $(USER_OPTIONS) -L$(LINK_PATH) --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
+ $(.config-cmd) mock.py --dll "$(>)" -o "$(<)" $(USER_OPTIONS) -L"$(LINK_PATH)" --static-lib=$(FINDLIBS-STATIC) --shared-lib=$(FINDLIBS-SHARED)
 }
 
 ''' % sys.executable.replace('\\', '\\\\'))
 
 def set_expected(t, markup):
+ verbose = "True" if t.verbose else "False"
   t.write('markup.py', '''
 import mockinfo
-info = mockinfo.MockInfo()
+info = mockinfo.MockInfo(%s)
 def source_file(name, contents):
   info.source_file(name, contents)
 def action(command, status=0):
   info.action(command, status)
-''' + markup)
+''' % verbose + markup)

Modified: branches/release/tools/build/v2/test/TestCmd.py
==============================================================================
--- branches/release/tools/build/v2/test/TestCmd.py (original)
+++ branches/release/tools/build/v2/test/TestCmd.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -21,6 +21,7 @@
 respectively. This allows for a distinction between an actual failed test and a
 test that could not be properly evaluated because of an external condition (such
 as a full file system or incorrect permissions).
+
 """
 
 # Copyright 2000 Steven Knight
@@ -57,10 +58,10 @@
 
 import os
 import os.path
-import popen2
 import re
 import shutil
 import stat
+import subprocess
 import sys
 import tempfile
 import traceback
@@ -102,9 +103,10 @@
 def fail_test(self=None, condition=True, function=None, skip=0):
     """Cause the test to fail.
 
- By default, the fail_test() method reports that the test FAILED and exits
- with a status of 1. If a condition argument is supplied, the test fails only
- if the condition is true.
+ By default, the fail_test() method reports that the test FAILED and exits
+ with a status of 1. If a condition argument is supplied, the test fails
+ only if the condition is true.
+
     """
     if not condition:
         return
@@ -131,9 +133,10 @@
 def no_result(self=None, condition=True, function=None, skip=0):
     """Causes a test to exit with no valid result.
 
- By default, the no_result() method reports NO RESULT for the test and exits
- with a status of 2. If a condition argument is supplied, the test fails only
- if the condition is true.
+ By default, the no_result() method reports NO RESULT for the test and
+ exits with a status of 2. If a condition argument is supplied, the test
+ fails only if the condition is true.
+
     """
     if not condition:
         return
@@ -158,9 +161,10 @@
 def pass_test(self=None, condition=True, function=None):
     """Causes a test to pass.
 
- By default, the pass_test() method reports PASSED for the test and exits
+ By default, the pass_test() method reports PASSED for the test and exits
     with a status of 0. If a condition argument is supplied, the test passes
     only if the condition is true.
+
     """
     if not condition:
         return
@@ -171,8 +175,10 @@
 
 
 def match_exact(lines=None, matches=None):
- """Returns whether the given lists or strings containing lines separated
+ """
+ Returns whether the given lists or strings containing lines separated
     using newline characters contain exactly the same data.
+
     """
     if not type(lines) is ListType:
         lines = split(lines, "\n")
@@ -187,9 +193,11 @@
 
 
 def match_re(lines=None, res=None):
- """Given lists or strings contain lines separated using newline characters.
+ """
+ Given lists or strings contain lines separated using newline characters.
     This function matches those lines one by one, interpreting the lines in the
     res parameter as regular expressions.
+
     """
     if not type(lines) is ListType:
         lines = split(lines, "\n")
@@ -204,42 +212,34 @@
 
 
 class TestCmd:
- """Class TestCmd.
- """
-
     def __init__(self, description=None, program=None, workdir=None,
         subdir=None, verbose=False, match=None, inpath=None):
 
         self._cwd = os.getcwd()
         self.description_set(description)
- if inpath:
- self.program = program
- else:
- self.program_set(program)
+ self.program_set(program, inpath)
         self.verbose_set(verbose)
- if not match is None:
- self.match_func = match
- else:
+ if match is None:
             self.match_func = match_re
+ else:
+ self.match_func = match
         self._dirlist = []
         self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
- if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
- self._preserve['pass_test'] = os.environ['PRESERVE']
- self._preserve['fail_test'] = os.environ['PRESERVE']
- self._preserve['no_result'] = os.environ['PRESERVE']
+ env = os.environ.get('PRESERVE')
+ if env:
+ self._preserve['pass_test'] = env
+ self._preserve['fail_test'] = env
+ self._preserve['no_result'] = env
         else:
- try:
- self._preserve['pass_test'] = os.environ['PRESERVE_PASS']
- except KeyError:
- pass
- try:
- self._preserve['fail_test'] = os.environ['PRESERVE_FAIL']
- except KeyError:
- pass
- try:
- self._preserve['no_result'] = os.environ['PRESERVE_NO_RESULT']
- except KeyError:
- pass
+ env = os.environ.get('PRESERVE_PASS')
+ if env is not None:
+ self._preserve['pass_test'] = env
+ env = os.environ.get('PRESERVE_FAIL')
+ if env is not None:
+ self._preserve['fail_test'] = env
+ env = os.environ.get('PRESERVE_PASS')
+ if env is not None:
+ self._preserve['PRESERVE_NO_RESULT'] = env
         self._stdout = []
         self._stderr = []
         self.status = None
@@ -254,7 +254,8 @@
         return "%x" % id(self)
 
     def cleanup(self, condition=None):
- """Removes any temporary working directories for the specified TestCmd
+ """
+ Removes any temporary working directories for the specified TestCmd
         environment. If the environment variable PRESERVE was set when the
         TestCmd environment was created, temporary working directories are not
         removed. If any of the environment variables PRESERVE_PASS,
@@ -264,9 +265,10 @@
         Temporary working directories are also preserved for conditions
         specified via the preserve method.
 
- Typically, this method is not called directly, but is used when the
+ Typically, this method is not called directly, but is used when the
         script exits to clean up temporary working directories as appropriate
         for the exit status.
+
         """
         if not self._dirlist:
             return
@@ -274,13 +276,13 @@
             condition = self.condition
         if self._preserve[condition]:
             for dir in self._dirlist:
- print "Preserved directory", dir
+ print("Preserved directory %s" % dir)
         else:
             list = self._dirlist[:]
             list.reverse()
             for dir in list:
                 self.writable(dir, 1)
- shutil.rmtree(dir, ignore_errors = 1)
+ shutil.rmtree(dir, ignore_errors=1)
 
         self._dirlist = []
         self.workdir = None
@@ -292,13 +294,11 @@
             pass
 
     def description_set(self, description):
- """Set the description of the functionality being tested.
- """
+ """Set the description of the functionality being tested."""
         self.description = description
 
     def fail_test(self, condition=True, function=None, skip=0):
- """Cause the test to fail.
- """
+ """Cause the test to fail."""
         if not condition:
             return
         self.condition = 'fail_test'
@@ -308,23 +308,19 @@
                   skip = skip)
 
     def match(self, lines, matches):
- """Compare actual and expected file contents.
- """
+ """Compare actual and expected file contents."""
         return self.match_func(lines, matches)
 
     def match_exact(self, lines, matches):
- """Compare actual and expected file contents.
- """
+ """Compare actual and expected file content exactly."""
         return match_exact(lines, matches)
 
     def match_re(self, lines, res):
- """Compare actual and expected file contents.
- """
+ """Compare file content with a regular expression."""
         return match_re(lines, res)
 
     def no_result(self, condition=True, function=None, skip=0):
- """Report that the test could not be run.
- """
+ """Report that the test could not be run."""
         if not condition:
             return
         self.condition = 'no_result'
@@ -334,38 +330,40 @@
                   skip = skip)
 
     def pass_test(self, condition=True, function=None):
- """Cause the test to pass.
- """
+ """Cause the test to pass."""
         if not condition:
             return
         self.condition = 'pass_test'
- pass_test(self = self, condition = condition, function = function)
+ pass_test(self, condition, function)
 
     def preserve(self, *conditions):
- """Arrange for the temporary working directories for the specified
+ """
+ Arrange for the temporary working directories for the specified
         TestCmd environment to be preserved for one or more conditions. If no
- conditions are specified, arranges for the temporary working directories
- to be preserved for all conditions.
+ conditions are specified, arranges for the temporary working
+ directories to be preserved for all conditions.
+
         """
         if conditions is ():
             conditions = ('pass_test', 'fail_test', 'no_result')
         for cond in conditions:
             self._preserve[cond] = 1
 
- def program_set(self, program):
- """Set the executable program or script to be tested.
- """
- if program and program[0] and not os.path.isabs(program[0]):
+ def program_set(self, program, inpath):
+ """Set the executable program or script to be tested."""
+ if not inpath and program and not os.path.isabs(program[0]):
             program[0] = os.path.join(self._cwd, program[0])
         self.program = program
 
     def read(self, file, mode='rb'):
- """Reads and returns the contents of the specified file name. The file
- name may be a list, in which case the elements are concatenated with the
- os.path.join() method. The file is assumed to be under the temporary
- working directory unless it is an absolute path name. The I/O mode for
- the file may be specified; it must begin with an 'r'. The default is
- 'rb' (binary read).
+ """
+ Reads and returns the contents of the specified file name. The file
+ name may be a list, in which case the elements are concatenated with
+ the os.path.join() method. The file is assumed to be under the
+ temporary working directory unless it is an absolute path name. The I/O
+ mode for the file may be specified and must begin with an 'r'. The
+ default is 'rb' (binary read).
+
         """
         if type(file) is ListType:
             file = apply(os.path.join, tuple(file))
@@ -375,18 +373,26 @@
             raise ValueError, "mode must begin with 'r'"
         return open(file, mode).read()
 
- def run(self, program=None, arguments=None, chdir=None, stdin=None):
- """Runs a test of the program or script for the test environment.
+ def run(self, program=None, arguments=None, chdir=None, stdin=None,
+ universal_newlines=True):
+ """
+ Runs a test of the program or script for the test environment.
         Standard output and error output are saved for future retrieval via the
         stdout() and stderr() methods.
+
+ 'universal_newlines' parameter controls how the child process
+ input/output streams are opened as defined for the same named Python
+ subprocess.POpen constructor parameter.
+
         """
         if chdir:
- oldcwd = os.getcwd()
             if not os.path.isabs(chdir):
                 chdir = os.path.join(self.workpath(chdir))
             if self.verbose:
                 sys.stderr.write("chdir(" + chdir + ")\n")
- os.chdir(chdir)
+ else:
+ chdir = self.workdir
+
         cmd = []
         if program and program[0]:
             if program[0] != self.program[0] and not os.path.isabs(program[0]):
@@ -398,142 +404,71 @@
             cmd += arguments.split(" ")
         if self.verbose:
             sys.stderr.write(join(cmd, " ") + "\n")
- try:
- p = popen2.Popen3(cmd, 1)
- except AttributeError:
- # We end up here in case the popen2.Popen3 class is not available
- # (e.g. on Windows). We will be using the os.popen3() Python API
- # which takes a string parameter and so needs its executable quoted
- # in case its name contains spaces.
- cmd[0] = '"' + cmd[0] + '"'
- command_string = join(cmd, " ")
- if ( os.name == 'nt' ):
- # This is a workaround for a longstanding Python bug on Windows
- # when using os.popen(), os.system() and similar functions to
- # execute a command containing quote characters. The bug seems
- # to be related to the quote stripping functionality used by the
- # Windows cmd.exe interpreter when its /S is not specified.
- #
- # Cleaned up quote from the cmd.exe help screen as displayed on
- # Windows XP SP2:
- #
- # 1. If all of the following conditions are met, then quote
- # characters on the command line are preserved:
- #
- # - no /S switch
- # - exactly two quote characters
- # - no special characters between the two quote
- # characters, where special is one of: &<>()@^|
- # - there are one or more whitespace characters between
- # the two quote characters
- # - the string between the two quote characters is the
- # name of an executable file.
- #
- # 2. Otherwise, old behavior is to see if the first character
- # is a quote character and if so, strip the leading
- # character and remove the last quote character on the
- # command line, preserving any text after the last quote
- # character.
- #
- # This causes some commands containing quotes not to be executed
- # correctly. For example:
- #
- # "\Long folder name\aaa.exe" --name="Jurko" --no-surname
- #
- # would get its outermost quotes stripped and would be executed
- # as:
- #
- # \Long folder name\aaa.exe" --name="Jurko --no-surname
- #
- # which would report an error about '\Long' not being a valid
- # command.
- #
- # cmd.exe help seems to indicate it would be enough to add an
- # extra space character in front of the command to avoid this
- # but this does not work, most likely due to the shell first
- # stripping all leading whitespace characters from the command.
- #
- # Solution implemented here is to quote the whole command in
- # case it contains any quote characters. Note thought this will
- # not work correctly should Python ever fix this bug.
- # (01.05.2008.) (Jurko)
- if command_string.find('"') != -1:
- command_string = '"' + command_string + '"'
- (tochild, fromchild, childerr) = os.popen3(command_string)
- if stdin:
- if type(stdin) is ListType:
- for line in stdin:
- tochild.write(line)
- else:
- tochild.write(stdin)
- tochild.close()
- self._stdout.append(fromchild.read())
- self._stderr.append(childerr.read())
- fromchild.close()
- self.status = childerr.close()
- if not self.status:
- self.status = 0
- except:
- raise
- else:
- if stdin:
- if type(stdin) is ListType:
- for line in stdin:
- p.tochild.write(line)
- else:
- p.tochild.write(stdin)
- p.tochild.close()
- self._stdout.append(p.fromchild.read())
- self._stderr.append(p.childerr.read())
- self.status = p.wait()
+ p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=chdir,
+ universal_newlines=universal_newlines)
+
+ if stdin:
+ if type(stdin) is ListType:
+ for line in stdin:
+ p.tochild.write(line)
+ else:
+ p.tochild.write(stdin)
+ out, err = p.communicate()
+ self._stdout.append(out)
+ self._stderr.append(err)
+ self.status = p.returncode
 
         if self.verbose:
             sys.stdout.write(self._stdout[-1])
             sys.stderr.write(self._stderr[-1])
 
- if chdir:
- os.chdir(oldcwd)
-
     def stderr(self, run=None):
- """Returns the error output from the specified run number. If there is
+ """
+ Returns the error output from the specified run number. If there is
         no specified run number, then returns the error output of the last run.
         If the run number is less than zero, then returns the error output from
         that many runs back from the current run.
+
         """
         if not run:
             run = len(self._stderr)
         elif run < 0:
             run = len(self._stderr) + run
- run = run - 1
- if (run < 0):
+ run -= 1
+ if run < 0:
             return ''
         return self._stderr[run]
 
     def stdout(self, run=None):
- """Returns the standard output from the specified run number. If there
- is no specified run number, then returns the standard output of the last
- run. If the run number is less than zero, then returns the standard
- output from that many runs back from the current run.
+ """
+ Returns the standard output from the specified run number. If there
+ is no specified run number, then returns the standard output of the
+ last run. If the run number is less than zero, then returns the
+ standard output from that many runs back from the current run.
+
         """
         if not run:
             run = len(self._stdout)
         elif run < 0:
             run = len(self._stdout) + run
- run = run - 1
- if (run < 0):
+ run -= 1
+ if run < 0:
             return ''
         return self._stdout[run]
 
     def subdir(self, *subdirs):
- """Create new subdirectories under the temporary working directory, one
+ """
+ Create new subdirectories under the temporary working directory, one
         for each argument. An argument may be a list, in which case the list
         elements are concatenated using the os.path.join() method.
         Subdirectories multiple levels deep must be created using a separate
         argument for each level:
 
- test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
+ test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
 
         Returns the number of subdirectories actually created.
+
         """
         count = 0
         for sub in subdirs:
@@ -547,14 +482,16 @@
             except:
                 pass
             else:
- count = count + 1
+ count += 1
         return count
 
- def unlink (self, file):
- """Unlinks the specified file name. The file name may be a list, in
+ def unlink(self, file):
+ """
+ Unlinks the specified file name. The file name may be a list, in
         which case the elements are concatenated using the os.path.join()
         method. The file is assumed to be under the temporary working directory
         unless it is an absolute path name.
+
         """
         if type(file) is ListType:
             file = apply(os.path.join, tuple(file))
@@ -563,19 +500,19 @@
         os.unlink(file)
 
     def verbose_set(self, verbose):
- """Set the verbose level.
- """
+ """Set the verbose level."""
         self.verbose = verbose
 
     def workdir_set(self, path):
- """Creates a temporary working directory with the specified path name.
- If the path is a null string (''), a unique directory name is created.
         """
+ Creates a temporary working directory with the specified path name.
+ If the path is a null string (''), a unique directory name is created.
 
+ """
         if os.path.isabs(path):
             self.workdir = path
         else:
- if (path != None):
+ if path != None:
                 if path == '':
                     path = tempfile.mktemp()
                 if path != None:
@@ -586,8 +523,8 @@
                     _Cleanup.index(self)
                 except ValueError:
                     _Cleanup.append(self)
- # We'd like to set self.workdir like this:
- # self.workdir = path
+ # We would like to set self.workdir like this:
+ # self.workdir = path
                 # But symlinks in the path will report things differently from
                 # os.getcwd(), so chdir there and back to fetch the canonical
                 # path.
@@ -599,31 +536,30 @@
                 self.workdir = None
 
     def workpath(self, *args):
- """Returns the absolute path name to a subdirectory or file within the
+ """
+ Returns the absolute path name to a subdirectory or file within the
         current temporary working directory. Concatenates the temporary working
- directory name with the specified arguments using the os.path.join()
- method.
+ directory name with the specified arguments using os.path.join().
+
         """
         return apply(os.path.join, (self.workdir,) + tuple(args))
 
     def writable(self, top, write):
- """Make the specified directory tree writable (write == 1) or not
- (write == None).
         """
+ Make the specified directory tree writable (write == 1) or not
+ (write == None).
 
+ """
         def _walk_chmod(arg, dirname, names):
             st = os.stat(dirname)
             os.chmod(dirname, arg(st[stat.ST_MODE]))
             for name in names:
- n = os.path.join(dirname, name)
- st = os.stat(n)
- os.chmod(n, arg(st[stat.ST_MODE]))
-
- def _mode_writable(mode):
- return stat.S_IMODE(mode|0200)
+ fullname = os.path.join(dirname, name)
+ st = os.stat(fullname)
+ os.chmod(fullname, arg(st[stat.ST_MODE]))
 
- def _mode_non_writable(mode):
- return stat.S_IMODE(mode&~0200)
+ _mode_writable = lambda mode: stat.S_IMODE(mode|0200)
+ _mode_non_writable = lambda mode: stat.S_IMODE(mode&~0200)
 
         if write:
             f = _mode_writable
@@ -635,12 +571,14 @@
             pass # Ignore any problems changing modes.
 
     def write(self, file, content, mode='wb'):
- """Writes the specified content text (second argument) to the specified
+ """
+ Writes the specified content text (second argument) to the specified
         file name (first argument). The file name may be a list, in which case
         the elements are concatenated using the os.path.join() method. The file
         is created under the temporary working directory. Any subdirectories in
- the path must already exist. The I/O mode for the file may be specified;
- it must begin with a 'w'. The default is 'wb' (binary write).
+ the path must already exist. The I/O mode for the file may be specified
+ and must begin with a 'w'. The default is 'wb' (binary write).
+
         """
         if type(file) is ListType:
             file = apply(os.path.join, tuple(file))

Modified: branches/release/tools/build/v2/test/abs_workdir.py
==============================================================================
--- branches/release/tools/build/v2/test/abs_workdir.py (original)
+++ branches/release/tools/build/v2/test/abs_workdir.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,31 +2,23 @@
 # Testing whether we may run a test in absolute directories. There are no tests
 # for temporary directories as this is implictly tested in a lot of other cases.
 
+# TODO: Move to a separate testing-system test group.
+# TODO: Make the test not display any output on success.
+# TODO: Make sure implemented path handling is correct under Windows, Cygwin &
+# Unix/Linux.
+
 import BoostBuild
 import os
-import string
-
-t = BoostBuild.Tester(arguments="pwd", executable="jam", workdir=os.getcwd(),
- pass_toolset=0)
-
-t.write("jamroot.jam", """
-actions print_pwd { pwd ; }
-print_pwd pwd ;
-ALWAYS pwd ;
-""")
-
-t.run_build_system(status=0)
+import tempfile
 
-if 'TMP' in os.environ:
- tmp_dir = os.environ.get('TMP')
-else:
- tmp_dir = "/tmp"
+t = BoostBuild.Tester(["-ffile.jam"], workdir=os.getcwd(), pass_d0=False,
+ pass_toolset=False)
 
-if string.rfind(t.stdout(), tmp_dir) != -1:
- t.fail_test(1)
+t.write("file.jam", "EXIT [ PWD ] : 0 ;")
 
-if string.rfind(t.stdout(), 'build/v2/test') == -1:
- t.fail_test(1)
+t.run_build_system()
+t.expect_output_lines("*%s*" % tempfile.gettempdir(), False)
+t.expect_output_lines("*build/v2/test*")
 
 t.run_build_system(status=1, subdir="/must/fail/with/absolute/path",
     stderr=None)

Modified: branches/release/tools/build/v2/test/absolute_sources.py
==============================================================================
--- branches/release/tools/build/v2/test/absolute_sources.py (original)
+++ branches/release/tools/build/v2/test/absolute_sources.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,47 +8,31 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
-path-constant TOP : . ;
-""")
-
-t.write("jamfile.jam", """
+t.write("jamroot.jam", "path-constant TOP : . ;")
+t.write("jamfile.jam", """\
 local pwd = [ PWD ] ;
 ECHO $(pwd) XXXXX ;
 exe hello : $(pwd)/hello.cpp $(TOP)/empty.cpp ;
 """)
-
 t.write("hello.cpp", "int main() {}\n")
-
 t.write("empty.cpp", "\n")
 
 t.run_build_system()
 t.expect_addition("bin/$toolset/debug/hello.exe")
 t.rm(".")
 
-# Test a contrived case. There, absolute name is used in a standalone project
-# (not Jamfile). Moreover, the target with an absolute name is returned by
-# 'alias' and used from another project.
-t.write("a.cpp", """
-int main() {}
-""")
-
-t.write("jamfile.jam", """
-exe a : /standalone//a ;
-""")
-
-t.write("jamroot.jam", """
-import standalone ;
-""")
-
-t.write("standalone.jam", """
+# Test a contrived case in which an absolute name is used in a standalone
+# project (not Jamfile). Moreover, the target with an absolute name is returned
+# via an 'alias' and used from another project.
+t.write("a.cpp", "int main() {}\n")
+t.write("jamfile.jam", "exe a : /standalone//a ;")
+t.write("jamroot.jam", "import standalone ;")
+t.write("standalone.jam", """\
 import project ;
-
 project.initialize $(__name__) ;
 project standalone ;
-
 local pwd = [ PWD ] ;
 alias a : $(pwd)/a.cpp ;
 """)
@@ -75,18 +59,10 @@
 t.rm(".")
 
 t.write("d1/jamroot.jam", "")
-
-t.write("d1/jamfile.jam", """
-exe a : a.cpp ;
-""")
-
-t.write("d1/a.cpp", """
-int main() {}
-""")
-
+t.write("d1/jamfile.jam", "exe a : a.cpp ;")
+t.write("d1/a.cpp", "int main() {}\n")
 t.write("d2/jamroot.jam", "")
-
-t.write("d2/jamfile.jam", """
+t.write("d2/jamfile.jam", """\
 local pwd = [ PWD ] ;
 alias x : $(pwd)/../d1//a ;
 """)

Modified: branches/release/tools/build/v2/test/alias.py
==============================================================================
--- branches/release/tools/build/v2/test/alias.py (original)
+++ branches/release/tools/build/v2/test/alias.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,18 +8,17 @@
 import BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # test_alias_rule()
 # -----------------
 #
-################################################################################
+###############################################################################
 
 def test_alias_rule(t):
- """Basic alias rule test.
- """
+ """Basic alias rule test."""
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe a : a.cpp ;
 exe b : b.cpp ;
 exe c : c.cpp ;
@@ -38,12 +37,12 @@
     t.write("s.cpp", "")
 
     # Check that targets to which "bin1" refers are updated, and only those.
- t.run_build_system("bin1")
+ t.run_build_system(["bin1"])
     t.expect_addition(BoostBuild.List("bin/$toolset/debug/") * "a.exe a.obj")
     t.expect_nothing_more()
 
     # Try again with "bin2"
- t.run_build_system("bin2")
+ t.run_build_system(["bin2"])
     t.expect_addition(BoostBuild.List("bin/$toolset/debug/") * "b.exe b.obj")
     t.expect_nothing_more()
 
@@ -56,26 +55,27 @@
     t.expect_nothing_more()
 
 
-################################################################################
+###############################################################################
 #
 # test_alias_source_usage_requirements()
 # --------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_alias_source_usage_requirements(t):
- """Check whether usage requirements are propagated via "alias". In case they
+ """
+ Check whether usage requirements are propagated via "alias". In case they
     are not, linking will fail as there will be no main() function defined
     anywhere in the source.
+
     """
-
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 lib l : l.cpp : : : <define>WANT_MAIN ;
 alias la : l ;
 exe main : main.cpp la ;
 """)
 
- t.write("l.cpp", """
+ t.write("l.cpp", """\
 void
 #if defined(_WIN32)
 __declspec(dllexport)
@@ -83,7 +83,7 @@
 foo() {}
 """)
 
- t.write("main.cpp", """
+ t.write("main.cpp", """\
 #ifdef WANT_MAIN
 int main() {}
 #endif
@@ -92,14 +92,16 @@
     t.run_build_system()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
-t = BoostBuild.Tester()
+# We do not pass the '-d0' option to Boost Build here to get more detailed
+# information in case of failure.
+t = BoostBuild.Tester(pass_d0=False, use_test_config=False)
 
 test_alias_rule(t)
 test_alias_source_usage_requirements(t)

Modified: branches/release/tools/build/v2/test/alternatives.py
==============================================================================
--- branches/release/tools/build/v2/test/alternatives.py (original)
+++ branches/release/tools/build/v2/test/alternatives.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,7 +10,7 @@
 import BoostBuild
 import string
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Test that basic alternatives selection works.
 t.write("jamroot.jam", "")
@@ -24,7 +24,7 @@
 
 t.write("a.cpp", "int main() {}\n")
 
-t.run_build_system("release")
+t.run_build_system(["release"])
 
 t.expect_addition("bin/$toolset/release/a.exe")
 
@@ -45,13 +45,13 @@
 t.run_build_system()
 t.expect_addition("bin/$toolset/debug/b.obj")
 
-t.run_build_system("X=on")
+t.run_build_system(["X=on"])
 t.expect_addition("bin/$toolset/debug/X-on/a.obj")
 
 t.rm("bin")
 
-# Test that everything works ok even with default build.
-t.write("jamfile.jam", """
+# Test that everything works ok even with the default build.
+t.write("jamfile.jam", """\
 exe a : a_empty.cpp : <variant>release ;
 exe a : a.cpp : <variant>debug ;
 """)
@@ -59,15 +59,15 @@
 t.run_build_system()
 t.expect_addition("bin/$toolset/debug/a.exe")
 
-# Test that only properties which are in build request matter for alternative
-# selection. IOW, alternative with <variant>release is better than one with
-# <variant>debug when building release version.
-t.write("jamfile.jam", """
+# Test that only properties which are in the build request matter for
+# alternative selection. IOW, alternative with <variant>release is better than
+# one with <variant>debug when building the release variant.
+t.write("jamfile.jam", """\
 exe a : a_empty.cpp : <variant>debug ;
 exe a : a.cpp : <variant>release ;
 """)
 
-t.run_build_system("release")
+t.run_build_system(["release"])
 t.expect_addition("bin/$toolset/release/a.exe")
 
 # Test that free properties do not matter. We really do not want <cxxflags>
@@ -78,29 +78,29 @@
 """)
 
 t.rm("bin/$toolset/release/a.exe")
-t.run_build_system("release define=FOO")
+t.run_build_system(["release", "define=FOO"])
 t.expect_addition("bin/$toolset/release/a.exe")
 
 # Test that ambiguity is reported correctly.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a_empty.cpp ;
 exe a : a.cpp ;
 """)
-t.run_build_system("--no-error-backtrace", status=None)
+t.run_build_system(["--no-error-backtrace"], status=None)
 t.fail_test(string.find(t.stdout(), "No best alternative") == -1)
 
 # Another ambiguity test: two matches properties in one alternative are neither
 # better nor worse than a single one in another alternative.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a_empty.cpp : <optimization>off <profiling>off ;
 exe a : a.cpp : <debug-symbols>on ;
 """)
 
-t.run_build_system("--no-error-backtrace", status=None)
+t.run_build_system(["--no-error-backtrace"], status=None)
 t.fail_test(string.find(t.stdout(), "No best alternative") == -1)
 
 # Test that we can have alternative without sources.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 alias specific-sources ;
 import feature ;
 feature.extend os : MAGIC ;

Modified: branches/release/tools/build/v2/test/build_dir.py
==============================================================================
--- branches/release/tools/build/v2/test/build_dir.py (original)
+++ branches/release/tools/build/v2/test/build_dir.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,12 +12,12 @@
 import string
 import os
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 
 # Test that top-level project can affect build dir.
 t.write("jamroot.jam", "import gcc ;")
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 project : build-dir build ;
 exe a : a.cpp ;
 build-project src ;
@@ -37,15 +37,16 @@
 # Test that building from child projects work.
 t.run_build_system(subdir='src')
 t.ignore("build/config.log")
+t.ignore("build/project-cache.jam")
 t.expect_nothing_more()
 
 # Test that project can override build dir.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp ;
 build-project src ;
 """)
 
-t.write("src/jamfile.jam", """
+t.write("src/jamfile.jam", """\
 project : build-dir build ;
 exe b : b.cpp ;
 """)
@@ -59,11 +60,11 @@
 t.write("jamroot.jam", "")
 
 # Test that we get an error when no project id is specified.
-t.run_build_system("--build-dir=foo")
+t.run_build_system(["--build-dir=foo"])
 t.fail_test(string.find(t.stdout(),
                    "warning: the --build-dir option will be ignored") == -1)
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 project foo ;
 exe a : a.cpp ;
 build-project sub ;
@@ -72,34 +73,34 @@
 t.write("sub/jamfile.jam", "exe b : b.cpp ;\n")
 t.write("sub/b.cpp", "int main() {}\n")
 
-t.run_build_system("--build-dir=build")
+t.run_build_system(["--build-dir=build"])
 t.expect_addition(["build/foo/$toolset/debug/a.exe",
                    "build/foo/sub/$toolset/debug/b.exe"])
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 project foo : build-dir bin.v2 ;
 exe a : a.cpp ;
 build-project sub ;
 """)
 
-t.run_build_system("--build-dir=build")
+t.run_build_system(["--build-dir=build"])
 t.expect_addition(["build/foo/bin.v2/$toolset/debug/a.exe",
                    "build/foo/bin.v2/sub/$toolset/debug/b.exe"])
 
 # Try building in subdir. We expect that the entire build tree with be in
-# 'sub/build'. Today, I am not sure if this is what the user expects, but let it
-# be.
+# 'sub/build'. Today, I am not sure if this is what the user expects, but let
+# it be.
 t.rm('build')
-t.run_build_system("--build-dir=build", subdir="sub")
+t.run_build_system(["--build-dir=build"], subdir="sub")
 t.expect_addition(["sub/build/foo/bin.v2/sub/$toolset/debug/b.exe"])
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 project foo : build-dir %s ;
 exe a : a.cpp ;
 build-project sub ;
 """ % string.replace(os.getcwd(), '\\', '\\\\'))
 
-t.run_build_system("--build-dir=build", status=1)
+t.run_build_system(["--build-dir=build"], status=1)
 t.fail_test(string.find(t.stdout(),
     "Absolute directory specified via 'build-dir' project attribute") == -1)
 

Modified: branches/release/tools/build/v2/test/build_file.py
==============================================================================
--- branches/release/tools/build/v2/test/build_file.py (original)
+++ branches/release/tools/build/v2/test/build_file.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,122 +1,122 @@
 #!/usr/bin/python
 
-# Copyright (C) Vladimir Prus 2006.
-# Copyright (C) Jurko Gospodnetic 2008.
-# 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)
+# Copyright (C) 2006. Vladimir Prus
+# Copyright (C) 2008. Jurko Gospodnetic
+# 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)
 
-# Tests that we explicitly request a file (not target) to be built by specifying
-# its name on the command line.
+# Tests that we explicitly request a file (not target) to be built by
+# specifying its name on the command line.
 
 import BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # test_building_file_from_specific_project()
 # ------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_building_file_from_specific_project():
- t = BoostBuild.Tester()
+ t = BoostBuild.Tester(use_test_config=False)
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe hello : hello.cpp ;
 exe hello2 : hello.cpp ;
 build-project sub ;
 """)
- t.write("hello.cpp", "int main() {}")
+ t.write("hello.cpp", "int main() {}\n")
     t.write("sub/jamfile.jam", """
 exe hello : hello.cpp ;
 exe hello2 : hello.cpp ;
 exe sub : hello.cpp ;
 """)
- t.write("sub/hello.cpp", "int main() {}")
+ t.write("sub/hello.cpp", "int main() {}\n")
 
- t.run_build_system("sub " + t.adjust_suffix("hello.obj"))
- t.expect_output_line("*depends on itself*", False)
+ t.run_build_system(["sub", t.adjust_suffix("hello.obj")])
+ t.expect_output_lines("*depends on itself*", False)
     t.expect_addition("sub/bin/$toolset/debug/hello.obj")
     t.expect_nothing_more()
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_building_file_from_specific_target()
 # -----------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_building_file_from_specific_target():
- t = BoostBuild.Tester()
+ t = BoostBuild.Tester(use_test_config=False)
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe hello1 : hello1.cpp ;
 exe hello2 : hello2.cpp ;
 exe hello3 : hello3.cpp ;
 """)
- t.write("hello1.cpp", "int main() {}")
- t.write("hello2.cpp", "int main() {}")
- t.write("hello3.cpp", "int main() {}")
+ t.write("hello1.cpp", "int main() {}\n")
+ t.write("hello2.cpp", "int main() {}\n")
+ t.write("hello3.cpp", "int main() {}\n")
 
- t.run_build_system("hello1 " + t.adjust_suffix("hello1.obj"))
+ t.run_build_system(["hello1", t.adjust_suffix("hello1.obj")])
     t.expect_addition("bin/$toolset/debug/hello1.obj")
     t.expect_nothing_more()
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_building_missing_file_from_specific_target()
 # -------------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_building_missing_file_from_specific_target():
- t = BoostBuild.Tester()
+ t = BoostBuild.Tester(use_test_config=False)
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe hello1 : hello1.cpp ;
 exe hello2 : hello2.cpp ;
 exe hello3 : hello3.cpp ;
 """)
- t.write("hello1.cpp", "int main() {}")
- t.write("hello2.cpp", "int main() {}")
- t.write("hello3.cpp", "int main() {}")
-
- t.run_build_system("hello1 " + t.adjust_suffix("hello2.obj"), status=1)
- t.expect_output_line("don't know how to make*" + t.adjust_suffix("hello2.obj"))
+ t.write("hello1.cpp", "int main() {}\n")
+ t.write("hello2.cpp", "int main() {}\n")
+ t.write("hello3.cpp", "int main() {}\n")
+
+ obj = t.adjust_suffix("hello2.obj")
+ t.run_build_system(["hello1", obj], status=1)
+ t.expect_output_lines("don't know how to make*" + obj)
     t.expect_nothing_more()
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_building_multiple_files_with_different_names()
 # ---------------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_building_multiple_files_with_different_names():
- t = BoostBuild.Tester()
+ t = BoostBuild.Tester(use_test_config=False)
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe hello1 : hello1.cpp ;
 exe hello2 : hello2.cpp ;
 exe hello3 : hello3.cpp ;
 """)
- t.write("hello1.cpp", "int main() {}")
- t.write("hello2.cpp", "int main() {}")
- t.write("hello3.cpp", "int main() {}")
-
- t.run_build_system(
- t.adjust_suffix("hello1.obj") + " " +
- t.adjust_suffix("hello2.obj"))
+ t.write("hello1.cpp", "int main() {}\n")
+ t.write("hello2.cpp", "int main() {}\n")
+ t.write("hello3.cpp", "int main() {}\n")
+
+ t.run_build_system([t.adjust_suffix("hello1.obj"), t.adjust_suffix(
+ "hello2.obj")])
     t.expect_addition("bin/$toolset/debug/hello1.obj")
     t.expect_addition("bin/$toolset/debug/hello2.obj")
     t.expect_nothing_more()
@@ -124,31 +124,31 @@
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_building_multiple_files_with_the_same_name()
 # -------------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_building_multiple_files_with_the_same_name():
- t = BoostBuild.Tester()
+ t = BoostBuild.Tester(use_test_config=False)
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe hello : hello.cpp ;
 exe hello2 : hello.cpp ;
 build-project sub ;
 """)
- t.write("hello.cpp", "int main() {}")
+ t.write("hello.cpp", "int main() {}\n")
     t.write("sub/jamfile.jam", """
 exe hello : hello.cpp ;
 exe hello2 : hello.cpp ;
 exe sub : hello.cpp ;
 """)
- t.write("sub/hello.cpp", "int main() {}")
+ t.write("sub/hello.cpp", "int main() {}\n")
 
- t.run_build_system(t.adjust_suffix("hello.obj"))
- t.expect_output_line("*depends on itself*", False)
+ t.run_build_system([t.adjust_suffix("hello.obj")])
+ t.expect_output_lines("*depends on itself*", False)
     t.expect_addition("bin/$toolset/debug/hello.obj")
     t.expect_addition("sub/bin/$toolset/debug/hello.obj")
     t.expect_nothing_more()
@@ -156,12 +156,12 @@
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
 test_building_file_from_specific_project()
 test_building_file_from_specific_target()

Modified: branches/release/tools/build/v2/test/build_no.py
==============================================================================
--- branches/release/tools/build/v2/test/build_no.py (original)
+++ branches/release/tools/build/v2/test/build_no.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,20 +9,15 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
-exe hello : hello.cpp : <variant>debug:<build>no ;
-""")
-
-t.write("hello.cpp", """
-int main() {}
-""")
+t.write("jamroot.jam", "exe hello : hello.cpp : <variant>debug:<build>no ;")
+t.write("hello.cpp", "int main() {}\n")
 
 t.run_build_system()
 t.expect_nothing_more()
 
-t.run_build_system("release")
+t.run_build_system(["release"])
 t.expect_addition("bin/$toolset/release/hello.exe")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/builtin_echo.py
==============================================================================
--- branches/release/tools/build/v2/test/builtin_echo.py (original)
+++ branches/release/tools/build/v2/test/builtin_echo.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,19 +9,19 @@
 import BoostBuild
 
 def test_echo(name):
- t = BoostBuild.Tester(pass_toolset=0)
+ t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0)
 
- t.write("file.jam", """
- %s ;
- UPDATE ;
- """ % name)
- t.run_build_system("-ffile.jam", stdout="\n")
+ t.write("file.jam", """\
+%s ;
+UPDATE ;
+""" % name)
+ t.run_build_system(stdout="\n")
 
- t.write("file.jam", """
- %s a message ;
- UPDATE ;
- """ % name)
- t.run_build_system("-ffile.jam", stdout="a message\n")
+ t.write("file.jam", """\
+%s a message ;
+UPDATE ;
+""" % name)
+ t.run_build_system(stdout="a message\n")
 
     t.cleanup()
 

Modified: branches/release/tools/build/v2/test/builtin_exit.py
==============================================================================
--- branches/release/tools/build/v2/test/builtin_exit.py (original)
+++ branches/release/tools/build/v2/test/builtin_exit.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,42 +9,30 @@
 import BoostBuild
 
 def test_exit(name):
- t = BoostBuild.Tester(pass_toolset=0)
+ t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0)
 
- t.write("file.jam", """
- %s ;
- """ % name)
- t.run_build_system("-ffile.jam", status=1, stdout="\n")
+ t.write("file.jam", "%s ;" % name)
+ t.run_build_system(status=1, stdout="\n")
     t.rm(".")
 
- t.write("file.jam", """
- %s : 0 ;
- """ % name)
- t.run_build_system("-ffile.jam", stdout="\n")
+ t.write("file.jam", "%s : 0 ;" % name)
+ t.run_build_system(stdout="\n")
     t.rm(".")
 
- t.write("file.jam", """
- %s : 1 ;
- """ % name)
- t.run_build_system("-ffile.jam", status=1, stdout="\n")
+ t.write("file.jam", "%s : 1 ;" % name)
+ t.run_build_system(status=1, stdout="\n")
     t.rm(".")
 
- t.write("file.jam", """
- %s : 2 ;
- """ % name)
- t.run_build_system("-ffile.jam", status=2, stdout="\n")
+ t.write("file.jam", "%s : 2 ;" % name)
+ t.run_build_system(status=2, stdout="\n")
     t.rm(".")
 
- t.write("file.jam", """
- %s a message ;
- """ % name)
- t.run_build_system("-ffile.jam", status=1, stdout="a message\n")
+ t.write("file.jam", "%s a message ;" % name)
+ t.run_build_system(status=1, stdout="a message\n")
     t.rm(".")
 
- t.write("file.jam", """
- %s a message : 0 ;
- """ % name)
- t.run_build_system("-ffile.jam", stdout="a message\n")
+ t.write("file.jam", "%s a message : 0 ;" % name)
+ t.run_build_system(stdout="a message\n")
     t.rm(".")
 
     t.cleanup()

Copied: branches/release/tools/build/v2/test/builtin_split_by_characters.py (from r78669, /trunk/tools/build/v2/test/builtin_split_by_characters.py)
==============================================================================
--- /trunk/tools/build/v2/test/builtin_split_by_characters.py (original)
+++ branches/release/tools/build/v2/test/builtin_split_by_characters.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 
 # Copyright 2012. Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # This tests the SPLIT_BY_CHARACTERS rule.
 
@@ -10,15 +11,15 @@
 
 def test_invalid(params, expected_error_line):
     t = BoostBuild.Tester(pass_toolset=0)
- t.write("file.jam", "SPLIT_BY_CHARACTERS %s ;\n" % params)
- t.run_build_system("-ffile.jam", status=1)
- t.expect_output_line("[*] %s" % expected_error_line)
+ t.write("file.jam", "SPLIT_BY_CHARACTERS %s ;" % params)
+ t.run_build_system(["-ffile.jam"], status=1)
+ t.expect_output_lines("[*] %s" % expected_error_line)
     t.cleanup()
 
 def test_valid():
     t = BoostBuild.Tester(pass_toolset=0)
- t.write("jamroot.jam",
-"""import assert ;
+ t.write("jamroot.jam", """\
+import assert ;
 
 assert.result FooBarBaz : SPLIT_BY_CHARACTERS FooBarBaz : "" ;
 assert.result FooBarBaz : SPLIT_BY_CHARACTERS FooBarBaz : x ;

Modified: branches/release/tools/build/v2/test/c_file.py
==============================================================================
--- branches/release/tools/build/v2/test/c_file.py (original)
+++ branches/release/tools/build/v2/test/c_file.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 project ;

Modified: branches/release/tools/build/v2/test/chain.py
==============================================================================
--- branches/release/tools/build/v2/test/chain.py (original)
+++ branches/release/tools/build/v2/test/chain.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,9 +1,9 @@
 #!/usr/bin/python
 
-# Copyright 2003 Dave Abrahams
-# Copyright 2002, 2003 Vladimir Prus
-# 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)
+# Copyright 2003 Dave Abrahams
+# Copyright 2002, 2003 Vladimir Prus
+# 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)
 
 # This tests that :
 # 1) the 'make' correctly assigns types to produced targets
@@ -11,7 +11,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # In order to correctly link this app, 'b.cpp', created by a 'make' rule, should
 # be compiled.
@@ -22,14 +22,14 @@
 import os ;
 if [ os.name ] = NT
 {
- actions create
+ actions create
     {
         echo int main() {} > $(<)
     }
 }
 else
 {
- actions create
+ actions create
     {
         echo "int main() {}" > $(<)
     }
@@ -39,7 +39,7 @@
 
 exe a : l dummy.cpp ;
 
-# Needs to be static lib for Windows - main() cannot appear in DLL.
+# Needs to be a static lib for Windows - main() cannot appear in DLL.
 static-lib l : a.cpp b.cpp ;
 
 make b.cpp : : create ;

Modified: branches/release/tools/build/v2/test/clean.py
==============================================================================
--- branches/release/tools/build/v2/test/clean.py (original)
+++ branches/release/tools/build/v2/test/clean.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,87 +7,75 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("a.cpp", """
-int main() {}
-""")
-
-t.write("jamroot.jam", """
-exe a : a.cpp sub1//sub1 sub2//sub2 sub3//sub3 ;
-""")
-
-t.write("sub1/jamfile.jam", """
+t.write("a.cpp", "int main() {}\n")
+t.write("jamroot.jam", "exe a : a.cpp sub1//sub1 sub2//sub2 sub3//sub3 ;")
+t.write("sub1/jamfile.jam", """\
 lib sub1 : sub1.cpp sub1_2 ../sub2//sub2 ;
 lib sub1_2 : sub1_2.cpp ;
 """)
 
-t.write("sub1/sub1.cpp", """
+t.write("sub1/sub1.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
 void sub1() {}
 """)
 
-t.write("sub1/sub1_2.cpp", """
+t.write("sub1/sub1_2.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
 void sub1() {}
 """)
 
-t.write("sub2/jamfile.jam", """
-lib sub2 : sub2.cpp ;
-""")
-
-t.write("sub2/sub2.cpp", """
+t.write("sub2/jamfile.jam", "lib sub2 : sub2.cpp ;")
+t.write("sub2/sub2.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
 void sub2() {}
 """)
 
-t.write("sub3/jamroot.jam", """
-lib sub3 : sub3.cpp ;
-""")
-
-t.write("sub3/sub3.cpp", """
+t.write("sub3/jamroot.jam", "lib sub3 : sub3.cpp ;")
+t.write("sub3/sub3.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
 void sub3() {}
 """)
 
-# The 'clean' should not remove files under separate jamroot.jam.
+# 'clean' should not remove files under separate jamroot.jam.
 t.run_build_system()
-t.run_build_system("--clean")
+t.run_build_system(["--clean"])
 t.expect_removal("bin/$toolset/debug/a.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
 t.expect_removal("sub2/bin/$toolset/debug/sub2.obj")
 t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
 
-# The 'clean-all' removes everything it can reach.
+# 'clean-all' removes everything it can reach.
 t.run_build_system()
-t.run_build_system("--clean-all")
+t.run_build_system(["--clean-all"])
 t.expect_removal("bin/$toolset/debug/a.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
 t.expect_removal("sub2/bin/$toolset/debug/sub2.obj")
 t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
 
-# The 'clean' together with project target removes only under that project.
+# 'clean' together with project target removes only under that project.
 t.run_build_system()
-t.run_build_system("sub1 --clean")
+t.run_build_system(["sub1", "--clean"])
 t.expect_nothing("bin/$toolset/debug/a.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
 t.expect_nothing("sub2/bin/$toolset/debug/sub2.obj")
 t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
 
-# And 'clean-all' removes everything.
+# 'clean-all' removes everything.
 t.run_build_system()
-t.run_build_system("sub1 --clean-all")
+t.run_build_system(["sub1", "--clean-all"])
 t.expect_nothing("bin/$toolset/debug/a.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
 t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
@@ -97,7 +85,7 @@
 # If main target is explicitly named, we should not remove files from other
 # targets.
 t.run_build_system()
-t.run_build_system("sub1//sub1 --clean")
+t.run_build_system(["sub1//sub1", "--clean"])
 t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
 t.expect_nothing("sub1/bin/$toolset/debug/sub1_2.obj")
 t.expect_nothing("sub2/bin/$toolset/debug/sub2.obj")
@@ -105,12 +93,12 @@
 
 # Regression test: sources of the 'cast' rule were mistakenly deleted.
 t.rm(".")
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 import cast ;
 cast a cpp : a.h ;
 """)
 t.write("a.h", "")
-t.run_build_system("--clean")
+t.run_build_system(["--clean"])
 t.expect_nothing("a.h")
 
 t.cleanup()

Copied: branches/release/tools/build/v2/test/collect_debug_info.py (from r78918, /trunk/tools/build/v2/test/collect_debug_info.py)
==============================================================================
--- /trunk/tools/build/v2/test/collect_debug_info.py (original)
+++ branches/release/tools/build/v2/test/collect_debug_info.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -23,7 +23,6 @@
 def collectDebugInfo():
     t = _init()
 
- dummyVars = ["WOOF_WOOFIE_%d" % x for x in xrange(4)]
     global tag
 
     tag = "Python version"
@@ -38,6 +37,41 @@
     except:
         _info_exc()
 
+ tag = "Boost Jam/Build version"
+ try:
+ _infoX(_getJamVersionInfo(t))
+ except:
+ _info_exc()
+
+ #_collectDebugInfo_environ()
+
+ # Report prepared annotations.
+ t.fail_test(1, dump_difference=False, dump_stdio=False, dump_stack=False)
+
+
+###############################################################################
+#
+# Private interface.
+#
+###############################################################################
+
+varSeparator = "###$^%~~~"
+
+
+def _collect(results, prefix, name, t):
+ results.append("%s - %s - os.getenv(): %r" % (prefix, name, os.getenv(
+ name)))
+ results.append("%s - %s - os.environ.get(): %r" % (prefix, name,
+ os.environ.get(name)))
+ external_values = _getExternalValues(t, name)
+ results.append("%s - %s - external: %r" % (prefix, name,
+ external_values[name]))
+
+
+def _collectDebugInfo_environ(t):
+ dummyVars = ["WOOF_WOOFIE_%d" % x for x in xrange(4)]
+ global tag
+
     tag = "XXX in os.environ"
     try:
         def f(name):
@@ -187,35 +221,12 @@
     except:
         _info_exc()
 
- # Avoid the 'changes caused by the last build command' report.
- if hasattr(t, 'difference'):
- del t.difference
-
- # Report prepared annotations.
- t.fail_test(1, dump_stdio=False, dump_stack=False)
-
-
-###############################################################################
-#
-# Private interface.
-#
-###############################################################################
-
-def _collect(results, prefix, name, t):
- results.append("%s - %s - os.getenv(): %r" % (prefix, name, os.getenv(
- name)))
- results.append("%s - %s - os.environ.get(): %r" % (prefix, name,
- os.environ.get(name)))
- external_values = _getExternalValues(t, name)
- results.append("%s - %s - external: %r" % (prefix, name,
- external_values[name]))
-
 
 def _getExternalValues(t, *args):
- t.run_build_system(" ".join("--var-name=%s" % x for x in args))
+ t.run_build_system(["---var-name=%s" % x for x in args])
     result = dict()
     for x in args:
- m = re.search(r"^\*\*\* %s: '(.*)' \*\*\*$" % x, t.stdout(),
+ m = re.search(r"^\*\*\*ENV\*\*\* %s: '(.*)' \*\*\*$" % x, t.stdout(),
             re.MULTILINE)
         if m:
             result[x] = m.group(1)
@@ -224,10 +235,41 @@
     return result
 
 
+def _getJamVersionInfo(t):
+ result = []
+
+ # JAM version variables.
+ t.run_build_system(["---version"])
+ for m in re.finditer(r"^\*\*\*VAR\*\*\* ([^:]*): (.*)\*\*\*$", t.stdout(),
+ re.MULTILINE):
+ name = m.group(1)
+ value = m.group(2)
+ if not value:
+ value = []
+ elif value[-1] == ' ':
+ value = value[:-1].split(varSeparator)
+ else:
+ value = "!!!INVALID!!! - '%s'" % value
+ result.append("%s = %s" % (name, value))
+ result.append("")
+
+ # bjam -v output.
+ t.run_build_system(["-v"])
+ result.append("--- output for 'bjam -v' ---")
+ result.append(t.stdout())
+
+ # bjam --version output.
+ t.run_build_system(["--version"], status=1)
+ result.append("--- output for 'bjam --version' ---")
+ result.append(t.stdout())
+
+ return result
+
+
 def _init():
     toolsetName = "__myDummyToolset__"
 
- t = BoostBuild.Tester("toolset=%s" % toolsetName, pass_toolset=False,
+ t = BoostBuild.Tester(["toolset=%s" % toolsetName], pass_toolset=False,
         use_test_config=False)
 
     # Prepare a dummy toolset so we do not get errors in case the default one
@@ -247,13 +289,22 @@
 
     t.write("jamroot.jam", """\
 import os ;
-local names = [ MATCH ^--var-name=(.*) : [ modules.peek : ARGV ] ] ;
+.argv = [ modules.peek : ARGV ] ;
+local names = [ MATCH ^---var-name=(.*) : $(.argv) ] ;
 for x in $(names)
 {
     value = [ os.environ $(x) ] ;
- ECHO *** $(x): '$(value)' *** ;
+ ECHO ***ENV*** $(x): '$(value)' *** ;
+}
+if ---version in $(.argv)
+{
+ for x in JAMVERSION JAM_VERSION JAMUNAME JAM_TIMESTAMP_RESOLUTION OS
+ {
+ v = [ modules.peek : $(x) ] ;
+ ECHO ***VAR*** $(x): "$(v:J=%s)" *** ;
+ }
 }
-""")
+""" % varSeparator)
 
     return t
 

Modified: branches/release/tools/build/v2/test/composite.py
==============================================================================
--- branches/release/tools/build/v2/test/composite.py (original)
+++ branches/release/tools/build/v2/test/composite.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 exe hello : hello.cpp : <variant>release ;

Modified: branches/release/tools/build/v2/test/conditionals.py
==============================================================================
--- branches/release/tools/build/v2/test/conditionals.py (original)
+++ branches/release/tools/build/v2/test/conditionals.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -3,17 +3,18 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2002, 2003, 2004 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Test conditional properties.
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Arrange a project which will build only if 'a.cpp' is compiled with "STATIC"
 # define.
-t.write("a.cpp", """
+t.write("a.cpp", """\
 #ifdef STATIC
 int main() {}
 #endif
@@ -21,7 +22,7 @@
 
 # Test conditionals in target requirements.
 t.write("jamroot.jam", "exe a : a.cpp : <link>static:<define>STATIC ;")
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("bin/$toolset/debug/link-static/a.exe")
 t.rm("bin")
 
@@ -30,18 +31,18 @@
 project : requirements <link>static:<define>STATIC ;
 exe a : a.cpp ;
 """)
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("bin/$toolset/debug/link-static/a.exe")
 t.rm("bin")
 
-# Regression test for a bug found by Ali Azarbayejani. Conditionals inside usage
-# requirement were not being evaluated.
+# Regression test for a bug found by Ali Azarbayejani. Conditionals inside
+# usage requirement were not being evaluated.
 t.write("jamroot.jam", """
 lib l : l.cpp : : : <link>static:<define>STATIC ;
 exe a : a.cpp l ;
 """)
 t.write("l.cpp", "int i;")
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("bin/$toolset/debug/link-static/a.exe")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/conditionals3.py
==============================================================================
--- branches/release/tools/build/v2/test/conditionals3.py (original)
+++ branches/release/tools/build/v2/test/conditionals3.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,7 +9,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 exe hello : hello.cpp : <variant>debug:<define>CLASS=Foo::Bar ;

Modified: branches/release/tools/build/v2/test/conditionals_multiple.py
==============================================================================
--- branches/release/tools/build/v2/test/conditionals_multiple.py (original)
+++ branches/release/tools/build/v2/test/conditionals_multiple.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 
 # Copyright 2008 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Tests that properties conditioned on more than one other property work as
 # expected.
@@ -10,34 +11,32 @@
 import BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # test_multiple_conditions()
 # --------------------------
 #
-################################################################################
+###############################################################################
 
 def test_multiple_conditions():
- """Basic tests for properties conditioned on multiple other properties.
- """
+ """Basic tests for properties conditioned on multiple other properties."""
 
- t = BoostBuild.Tester("--user-config= --ignore-site-config toolset=testToolset",
- pass_toolset=False, use_test_config=False)
+ t = BoostBuild.Tester(["--user-config=", "--ignore-site-config",
+ "toolset=testToolset"], pass_toolset=False, use_test_config=False)
 
- t.write("testToolset.jam", """
+ t.write("testToolset.jam", """\
 import feature ;
 feature.extend toolset : testToolset ;
 rule init ( ) { }
 """)
 
- t.write("testToolset.py", """
+ t.write("testToolset.py", """\
 from b2.build import feature
 feature.extend('toolset', ["testToolset"])
-def init ( ):
- pass
+def init ( ): pass
 """)
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 import feature ;
 import notfile ;
 import toolset ;
@@ -71,86 +70,87 @@
     <aaa>1,<bbb>1,<ccc>1:<description>a1-b1-c1 ;
 """)
 
- t.run_build_system("aaa=1 bbb=1 ccc=1")
- t.expect_output_line("description: /d/" )
- t.expect_output_line("description: /a0/" , False)
- t.expect_output_line("description: /a1/" )
- t.expect_output_line("description: /a0-b0/" , False)
- t.expect_output_line("description: /a0-b1/" , False)
- t.expect_output_line("description: /a1-b0/" , False)
- t.expect_output_line("description: /a1-b1/" )
- t.expect_output_line("description: /a0-b0-c0/", False)
- t.expect_output_line("description: /a0-b0-c1/", False)
- t.expect_output_line("description: /a0-b1-c1/", False)
- t.expect_output_line("description: /a1-b0-c1/", False)
- t.expect_output_line("description: /a1-b1-c0/", False)
- t.expect_output_line("description: /a1-b1-c1/" )
-
- t.run_build_system("aaa=0 bbb=0 ccc=1")
- t.expect_output_line("description: /d/" )
- t.expect_output_line("description: /a0/" )
- t.expect_output_line("description: /a1/" , False)
- t.expect_output_line("description: /a0-b0/" )
- t.expect_output_line("description: /a0-b1/" , False)
- t.expect_output_line("description: /a1-b0/" , False)
- t.expect_output_line("description: /a1-b1/" , False)
- t.expect_output_line("description: /a0-b0-c0/", False)
- t.expect_output_line("description: /a0-b0-c1/" )
- t.expect_output_line("description: /a0-b1-c1/", False)
- t.expect_output_line("description: /a1-b0-c1/", False)
- t.expect_output_line("description: /a1-b1-c0/", False)
- t.expect_output_line("description: /a1-b1-c1/", False)
-
- t.run_build_system("aaa=0 bbb=0 ccc=0")
- t.expect_output_line("description: /d/" )
- t.expect_output_line("description: /a0/" )
- t.expect_output_line("description: /a1/" , False)
- t.expect_output_line("description: /a0-b0/" )
- t.expect_output_line("description: /a0-b1/" , False)
- t.expect_output_line("description: /a1-b0/" , False)
- t.expect_output_line("description: /a1-b1/" , False)
- t.expect_output_line("description: /a0-b0-c0/" )
- t.expect_output_line("description: /a0-b0-c1/", False)
- t.expect_output_line("description: /a0-b1-c1/", False)
- t.expect_output_line("description: /a1-b0-c1/", False)
- t.expect_output_line("description: /a1-b1-c0/", False)
- t.expect_output_line("description: /a1-b1-c1/", False)
+ t.run_build_system(["aaa=1", "bbb=1", "ccc=1"])
+ t.expect_output_lines("description: /d/" )
+ t.expect_output_lines("description: /a0/" , False)
+ t.expect_output_lines("description: /a1/" )
+ t.expect_output_lines("description: /a0-b0/" , False)
+ t.expect_output_lines("description: /a0-b1/" , False)
+ t.expect_output_lines("description: /a1-b0/" , False)
+ t.expect_output_lines("description: /a1-b1/" )
+ t.expect_output_lines("description: /a0-b0-c0/", False)
+ t.expect_output_lines("description: /a0-b0-c1/", False)
+ t.expect_output_lines("description: /a0-b1-c1/", False)
+ t.expect_output_lines("description: /a1-b0-c1/", False)
+ t.expect_output_lines("description: /a1-b1-c0/", False)
+ t.expect_output_lines("description: /a1-b1-c1/" )
+
+ t.run_build_system(["aaa=0", "bbb=0", "ccc=1"])
+ t.expect_output_lines("description: /d/" )
+ t.expect_output_lines("description: /a0/" )
+ t.expect_output_lines("description: /a1/" , False)
+ t.expect_output_lines("description: /a0-b0/" )
+ t.expect_output_lines("description: /a0-b1/" , False)
+ t.expect_output_lines("description: /a1-b0/" , False)
+ t.expect_output_lines("description: /a1-b1/" , False)
+ t.expect_output_lines("description: /a0-b0-c0/", False)
+ t.expect_output_lines("description: /a0-b0-c1/" )
+ t.expect_output_lines("description: /a0-b1-c1/", False)
+ t.expect_output_lines("description: /a1-b0-c1/", False)
+ t.expect_output_lines("description: /a1-b1-c0/", False)
+ t.expect_output_lines("description: /a1-b1-c1/", False)
+
+ t.run_build_system(["aaa=0", "bbb=0", "ccc=0"])
+ t.expect_output_lines("description: /d/" )
+ t.expect_output_lines("description: /a0/" )
+ t.expect_output_lines("description: /a1/" , False)
+ t.expect_output_lines("description: /a0-b0/" )
+ t.expect_output_lines("description: /a0-b1/" , False)
+ t.expect_output_lines("description: /a1-b0/" , False)
+ t.expect_output_lines("description: /a1-b1/" , False)
+ t.expect_output_lines("description: /a0-b0-c0/" )
+ t.expect_output_lines("description: /a0-b0-c1/", False)
+ t.expect_output_lines("description: /a0-b1-c1/", False)
+ t.expect_output_lines("description: /a1-b0-c1/", False)
+ t.expect_output_lines("description: /a1-b1-c0/", False)
+ t.expect_output_lines("description: /a1-b1-c1/", False)
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_multiple_conditions_with_toolset_version()
 # -----------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_multiple_conditions_with_toolset_version():
- """Regression tests for properties conditioned on the toolset version
- subfeature and some additional properties.
     """
+ Regression tests for properties conditioned on the toolset version
+ subfeature and some additional properties.
 
+ """
     toolset = "testToolset" ;
 
- t = BoostBuild.Tester("--user-config= --ignore-site-config", pass_toolset=False, use_test_config=False)
+ t = BoostBuild.Tester(["--user-config=", "--ignore-site-config"],
+ pass_toolset=False, use_test_config=False)
 
- t.write( toolset + ".jam", """
+ t.write(toolset + ".jam", """\
 import feature ;
 feature.extend toolset : %(toolset)s ;
 feature.subfeature toolset %(toolset)s : version : 0 1 ;
 rule init ( version ? ) { }
 """ % {"toolset": toolset})
 
- t.write( "testToolset.py", """
+ t.write("testToolset.py", """\
 from b2.build import feature
-feature.extend('toolset', ["testToolset"])
-feature.subfeature('toolset',"testToolset","version",['0','1'])
-def init ( version ):
- pass
- """)
+feature.extend('toolset', ["%(toolset)s"])
+feature.subfeature('toolset', "%(toolset)s", "version", ['0','1'])
+def init ( version ): pass
+""" % {"toolset": toolset})
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 import feature ;
 import notfile ;
 import toolset ;
@@ -222,91 +222,91 @@
     <bbb>1,<aaa>1,<toolset>testToolset-1:<description>b1-a1-t1 ;
 """)
 
- t.run_build_system("aaa=1 bbb=1 ccc=1 toolset=%s-0" % toolset)
- t.expect_output_line("description: /t-a0/" , False)
- t.expect_output_line("description: /t-a1/" )
- t.expect_output_line("description: /t0-a0/" , False)
- t.expect_output_line("description: /t0-a1/" )
- t.expect_output_line("description: /t1-a0/" , False)
- t.expect_output_line("description: /t1-a1/" , False)
- t.expect_output_line("description: /t-a0-b0/" , False)
- t.expect_output_line("description: /t-a0-b1/" , False)
- t.expect_output_line("description: /t-a1-b0/" , False)
- t.expect_output_line("description: /t-a1-b1/" )
- t.expect_output_line("description: /a0-t-b0/" , False)
- t.expect_output_line("description: /a0-t-b1/" , False)
- t.expect_output_line("description: /a1-t-b0/" , False)
- t.expect_output_line("description: /a1-t-b1/" )
- t.expect_output_line("description: /a0-b0-t/" , False)
- t.expect_output_line("description: /a0-b1-t/" , False)
- t.expect_output_line("description: /a1-b0-t/" , False)
- t.expect_output_line("description: /a1-b1-t/" )
- t.expect_output_line("description: /t0-a0-b0/", False)
- t.expect_output_line("description: /t0-a0-b1/", False)
- t.expect_output_line("description: /t0-a1-b0/", False)
- t.expect_output_line("description: /t0-a1-b1/" )
- t.expect_output_line("description: /t1-a0-b0/", False)
- t.expect_output_line("description: /t1-a0-b1/", False)
- t.expect_output_line("description: /t1-a1-b0/", False)
- t.expect_output_line("description: /t1-a1-b1/", False)
- t.expect_output_line("description: /a0-t1-b0/", False)
- t.expect_output_line("description: /a0-t1-b1/", False)
- t.expect_output_line("description: /a1-t0-b0/", False)
- t.expect_output_line("description: /a1-t0-b1/" )
- t.expect_output_line("description: /b0-a1-t0/", False)
- t.expect_output_line("description: /b0-a0-t1/", False)
- t.expect_output_line("description: /b0-a1-t1/", False)
- t.expect_output_line("description: /b1-a0-t1/", False)
- t.expect_output_line("description: /b1-a1-t0/" )
- t.expect_output_line("description: /b1-a1-t1/", False)
-
- t.run_build_system("aaa=1 bbb=1 ccc=1 toolset=%s-1" % toolset)
- t.expect_output_line("description: /t-a0/" , False)
- t.expect_output_line("description: /t-a1/" )
- t.expect_output_line("description: /t0-a0/" , False)
- t.expect_output_line("description: /t0-a1/" , False)
- t.expect_output_line("description: /t1-a0/" , False)
- t.expect_output_line("description: /t1-a1/" )
- t.expect_output_line("description: /t-a0-b0/" , False)
- t.expect_output_line("description: /t-a0-b1/" , False)
- t.expect_output_line("description: /t-a1-b0/" , False)
- t.expect_output_line("description: /t-a1-b1/" )
- t.expect_output_line("description: /a0-t-b0/" , False)
- t.expect_output_line("description: /a0-t-b1/" , False)
- t.expect_output_line("description: /a1-t-b0/" , False)
- t.expect_output_line("description: /a1-t-b1/" )
- t.expect_output_line("description: /a0-b0-t/" , False)
- t.expect_output_line("description: /a0-b1-t/" , False)
- t.expect_output_line("description: /a1-b0-t/" , False)
- t.expect_output_line("description: /a1-b1-t/" )
- t.expect_output_line("description: /t0-a0-b0/", False)
- t.expect_output_line("description: /t0-a0-b1/", False)
- t.expect_output_line("description: /t0-a1-b0/", False)
- t.expect_output_line("description: /t0-a1-b1/", False)
- t.expect_output_line("description: /t1-a0-b0/", False)
- t.expect_output_line("description: /t1-a0-b1/", False)
- t.expect_output_line("description: /t1-a1-b0/", False)
- t.expect_output_line("description: /t1-a1-b1/" )
- t.expect_output_line("description: /a0-t1-b0/", False)
- t.expect_output_line("description: /a0-t1-b1/", False)
- t.expect_output_line("description: /a1-t0-b0/", False)
- t.expect_output_line("description: /a1-t0-b1/", False)
- t.expect_output_line("description: /b0-a1-t0/", False)
- t.expect_output_line("description: /b0-a0-t1/", False)
- t.expect_output_line("description: /b0-a1-t1/", False)
- t.expect_output_line("description: /b1-a0-t1/", False)
- t.expect_output_line("description: /b1-a1-t0/", False)
- t.expect_output_line("description: /b1-a1-t1/" )
+ t.run_build_system(["aaa=1", "bbb=1", "ccc=1", "toolset=%s-0" % toolset])
+ t.expect_output_lines("description: /t-a0/" , False)
+ t.expect_output_lines("description: /t-a1/" )
+ t.expect_output_lines("description: /t0-a0/" , False)
+ t.expect_output_lines("description: /t0-a1/" )
+ t.expect_output_lines("description: /t1-a0/" , False)
+ t.expect_output_lines("description: /t1-a1/" , False)
+ t.expect_output_lines("description: /t-a0-b0/" , False)
+ t.expect_output_lines("description: /t-a0-b1/" , False)
+ t.expect_output_lines("description: /t-a1-b0/" , False)
+ t.expect_output_lines("description: /t-a1-b1/" )
+ t.expect_output_lines("description: /a0-t-b0/" , False)
+ t.expect_output_lines("description: /a0-t-b1/" , False)
+ t.expect_output_lines("description: /a1-t-b0/" , False)
+ t.expect_output_lines("description: /a1-t-b1/" )
+ t.expect_output_lines("description: /a0-b0-t/" , False)
+ t.expect_output_lines("description: /a0-b1-t/" , False)
+ t.expect_output_lines("description: /a1-b0-t/" , False)
+ t.expect_output_lines("description: /a1-b1-t/" )
+ t.expect_output_lines("description: /t0-a0-b0/", False)
+ t.expect_output_lines("description: /t0-a0-b1/", False)
+ t.expect_output_lines("description: /t0-a1-b0/", False)
+ t.expect_output_lines("description: /t0-a1-b1/" )
+ t.expect_output_lines("description: /t1-a0-b0/", False)
+ t.expect_output_lines("description: /t1-a0-b1/", False)
+ t.expect_output_lines("description: /t1-a1-b0/", False)
+ t.expect_output_lines("description: /t1-a1-b1/", False)
+ t.expect_output_lines("description: /a0-t1-b0/", False)
+ t.expect_output_lines("description: /a0-t1-b1/", False)
+ t.expect_output_lines("description: /a1-t0-b0/", False)
+ t.expect_output_lines("description: /a1-t0-b1/" )
+ t.expect_output_lines("description: /b0-a1-t0/", False)
+ t.expect_output_lines("description: /b0-a0-t1/", False)
+ t.expect_output_lines("description: /b0-a1-t1/", False)
+ t.expect_output_lines("description: /b1-a0-t1/", False)
+ t.expect_output_lines("description: /b1-a1-t0/" )
+ t.expect_output_lines("description: /b1-a1-t1/", False)
+
+ t.run_build_system(["aaa=1", "bbb=1", "ccc=1", "toolset=%s-1" % toolset])
+ t.expect_output_lines("description: /t-a0/" , False)
+ t.expect_output_lines("description: /t-a1/" )
+ t.expect_output_lines("description: /t0-a0/" , False)
+ t.expect_output_lines("description: /t0-a1/" , False)
+ t.expect_output_lines("description: /t1-a0/" , False)
+ t.expect_output_lines("description: /t1-a1/" )
+ t.expect_output_lines("description: /t-a0-b0/" , False)
+ t.expect_output_lines("description: /t-a0-b1/" , False)
+ t.expect_output_lines("description: /t-a1-b0/" , False)
+ t.expect_output_lines("description: /t-a1-b1/" )
+ t.expect_output_lines("description: /a0-t-b0/" , False)
+ t.expect_output_lines("description: /a0-t-b1/" , False)
+ t.expect_output_lines("description: /a1-t-b0/" , False)
+ t.expect_output_lines("description: /a1-t-b1/" )
+ t.expect_output_lines("description: /a0-b0-t/" , False)
+ t.expect_output_lines("description: /a0-b1-t/" , False)
+ t.expect_output_lines("description: /a1-b0-t/" , False)
+ t.expect_output_lines("description: /a1-b1-t/" )
+ t.expect_output_lines("description: /t0-a0-b0/", False)
+ t.expect_output_lines("description: /t0-a0-b1/", False)
+ t.expect_output_lines("description: /t0-a1-b0/", False)
+ t.expect_output_lines("description: /t0-a1-b1/", False)
+ t.expect_output_lines("description: /t1-a0-b0/", False)
+ t.expect_output_lines("description: /t1-a0-b1/", False)
+ t.expect_output_lines("description: /t1-a1-b0/", False)
+ t.expect_output_lines("description: /t1-a1-b1/" )
+ t.expect_output_lines("description: /a0-t1-b0/", False)
+ t.expect_output_lines("description: /a0-t1-b1/", False)
+ t.expect_output_lines("description: /a1-t0-b0/", False)
+ t.expect_output_lines("description: /a1-t0-b1/", False)
+ t.expect_output_lines("description: /b0-a1-t0/", False)
+ t.expect_output_lines("description: /b0-a0-t1/", False)
+ t.expect_output_lines("description: /b0-a1-t1/", False)
+ t.expect_output_lines("description: /b1-a0-t1/", False)
+ t.expect_output_lines("description: /b1-a1-t0/", False)
+ t.expect_output_lines("description: /b1-a1-t1/" )
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
 test_multiple_conditions()
 test_multiple_conditions_with_toolset_version()

Modified: branches/release/tools/build/v2/test/configuration.py
==============================================================================
--- branches/release/tools/build/v2/test/configuration.py (original)
+++ branches/release/tools/build/v2/test/configuration.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,118 +1,328 @@
 #!/usr/bin/python
 
-# Copyright 2008 Jurko Gospodnetic
+# Copyright 2008, 2012 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
-# Test that Boost Build configuration file handling.
+# Test Boost Build configuration file handling.
 
 import BoostBuild
+
+import os
 import os.path
-import string
+import re
 
 
-################################################################################
+###############################################################################
 #
 # test_user_configuration()
 # -------------------------
 #
-################################################################################
+###############################################################################
 
 def test_user_configuration():
- """Test Boost Build user configuration handling. Both relative and absolute
- path handling is tested.
     """
+ Test Boost Build user configuration handling. Both relative and absolute
+ path handling is tested.
 
- t = BoostBuild.Tester("--debug-configuration", pass_toolset=False,
- use_test_config=False)
+ """
 
- implicitConfigLoadMessage = "notice: Loading user-config configuration file: *"
- explicitConfigLoadMessage = "notice: Loading explicitly specified user configuration file:"
+ implicitConfigLoadMessage = \
+ "notice: Loading user-config configuration file: *"
+ explicitConfigLoadMessage = \
+ "notice: Loading explicitly specified user configuration file:"
+ disabledConfigLoadMessage = \
+ "notice: User configuration file loading explicitly disabled."
     testMessage = "_!_!_!_!_!_!_!_!_ %s _!_!_!_!_!_!_!_!_"
     toolsetName = "__myDummyToolset__"
     subdirName = "ASubDirectory"
     configFileNames = ["ups_lala_1.jam", "ups_lala_2.jam",
         os.path.join(subdirName, "ups_lala_3.jam")]
 
+ t = BoostBuild.Tester(["toolset=%s" % toolsetName,
+ "--debug-configuration"], pass_toolset=False, use_test_config=False)
+
     for configFileName in configFileNames:
         message = "ECHO \"%s\" ;" % testMessage % configFileName
- # We need to double any backslashes in the message or Jam will interpret
- # them as escape characters.
+ # We need to double any backslashes in the message or Jam will
+ # interpret them as escape characters.
         t.write(configFileName, message.replace("\\", "\\\\"))
 
- # Prepare a dummy toolset so we do not get errors in case the default one is
- # not found.
- t.write(toolsetName + ".jam", """
+ # Prepare a dummy toolset so we do not get errors in case the default one
+ # is not found.
+ t.write(toolsetName + ".jam", """\
 import feature ;
 feature.extend toolset : %s ;
 rule init ( ) { }
-""" % toolsetName )
+""" % toolsetName)
 
- # Python version of same dummy toolset.
- t.write(toolsetName + ".py", """
+ # Python version of the same dummy toolset.
+ t.write(toolsetName + ".py", """\
 from b2.build import feature
 feature.extend('toolset', ['%s'])
 def init(): pass
-""" % toolsetName )
-
- t.write("jamroot.jam", "using %s ;" % toolsetName)
-
- t.run_build_system()
- t.expect_output_line(explicitConfigLoadMessage, False)
- t.expect_output_line(testMessage % configFileNames[0], False)
- t.expect_output_line(testMessage % configFileNames[1], False)
- t.expect_output_line(testMessage % configFileNames[2], False)
-
- t.run_build_system("--user-config=")
- t.expect_output_line(implicitConfigLoadMessage, False)
- t.expect_output_line(explicitConfigLoadMessage, False)
- t.expect_output_line(testMessage % configFileNames[0], False)
- t.expect_output_line(testMessage % configFileNames[1], False)
- t.expect_output_line(testMessage % configFileNames[2], False)
-
- t.run_build_system('--user-config=""')
- t.expect_output_line(implicitConfigLoadMessage, False)
- t.expect_output_line(explicitConfigLoadMessage, False)
- t.expect_output_line(testMessage % configFileNames[0], False)
- t.expect_output_line(testMessage % configFileNames[1], False)
- t.expect_output_line(testMessage % configFileNames[2], False)
-
- t.run_build_system('--user-config="%s"' % configFileNames[0])
- t.expect_output_line(implicitConfigLoadMessage, False)
- t.expect_output_line(explicitConfigLoadMessage)
- t.expect_output_line(testMessage % configFileNames[0] )
- t.expect_output_line(testMessage % configFileNames[1], False)
- t.expect_output_line(testMessage % configFileNames[2], False)
-
- t.run_build_system('--user-config="%s"' % configFileNames[2])
- t.expect_output_line(implicitConfigLoadMessage, False)
- t.expect_output_line(explicitConfigLoadMessage)
- t.expect_output_line(testMessage % configFileNames[0], False)
- t.expect_output_line(testMessage % configFileNames[1], False)
- t.expect_output_line(testMessage % configFileNames[2] )
-
- t.run_build_system('--user-config="%s"' % os.path.abspath(configFileNames[1]))
- t.expect_output_line(implicitConfigLoadMessage, False)
- t.expect_output_line(explicitConfigLoadMessage)
- t.expect_output_line(testMessage % configFileNames[0], False)
- t.expect_output_line(testMessage % configFileNames[1] )
- t.expect_output_line(testMessage % configFileNames[2], False)
-
- t.run_build_system('--user-config="%s"' % os.path.abspath(configFileNames[2]))
- t.expect_output_line(implicitConfigLoadMessage, False)
- t.expect_output_line(explicitConfigLoadMessage)
- t.expect_output_line(testMessage % configFileNames[0], False)
- t.expect_output_line(testMessage % configFileNames[1], False)
- t.expect_output_line(testMessage % configFileNames[2] )
+""" % toolsetName)
+
+ t.write("jamroot.jam", """\
+local test-index = [ MATCH ---test-id---=(.*) : [ modules.peek : ARGV ] ] ;
+ECHO test-index: $(test-index:E=(unknown)) ;
+""")
+
+ class LocalTester:
+ def __init__(self, tester):
+ self.__tester = tester
+ self.__test_ids = []
+
+ def __assertionFailure(self, message):
+ BoostBuild.annotation("failure", "Internal test assertion failure "
+ "- %s" % message)
+ self.__tester.fail_test(1)
+
+ def __call__(self, test_id, env, extra_args=None, *args, **kwargs):
+ if env == "" and not canSetEmptyEnvironmentVariable:
+ self.__assertionFailure("Can not set empty environment "
+ "variables on this platform.")
+ self.__registerTestId(str(test_id))
+ if extra_args is None:
+ extra_args = []
+ extra_args.append("---test-id---=%s" % test_id)
+ env_name = "BOOST_BUILD_USER_CONFIG"
+ previous_env = os.environ.get(env_name)
+ _env_set(env_name, env)
+ try:
+ self.__tester.run_build_system(extra_args, *args, **kwargs)
+ finally:
+ _env_set(env_name, previous_env)
+
+ def __registerTestId(self, test_id):
+ if test_id in self.__test_ids:
+ self.__assertionFailure("Multiple test cases encountered "
+ "using the same test id '%s'." % test_id)
+ self.__test_ids.append(test_id)
+
+ test = LocalTester(t)
+
+ test(1, None)
+ t.expect_output_lines(explicitConfigLoadMessage, False)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(2, None, ["--user-config="])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage, False)
+ t.expect_output_lines(disabledConfigLoadMessage)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(3, None, ['--user-config=""'])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage, False)
+ t.expect_output_lines(disabledConfigLoadMessage)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(4, None, ['--user-config="%s"' % configFileNames[0]])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0])
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(5, None, ['--user-config="%s"' % configFileNames[2]])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2])
+
+ test(6, None, ['--user-config="%s"' % os.path.abspath(configFileNames[1])])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1])
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(7, None, ['--user-config="%s"' % os.path.abspath(configFileNames[2])])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2])
+
+ if canSetEmptyEnvironmentVariable:
+ test(8, "")
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage, False)
+ t.expect_output_lines(disabledConfigLoadMessage, True)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(9, '""')
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage, False)
+ t.expect_output_lines(disabledConfigLoadMessage)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(10, configFileNames[1])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1])
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(11, configFileNames[1], ['--user-config=""'])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage, False)
+ t.expect_output_lines(disabledConfigLoadMessage)
+ t.expect_output_lines(testMessage % configFileNames[0], False)
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(12, configFileNames[1], ['--user-config="%s"' % configFileNames[0]])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0])
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ if canSetEmptyEnvironmentVariable:
+ test(13, "", ['--user-config="%s"' % configFileNames[0]])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0])
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(14, '""', ['--user-config="%s"' % configFileNames[0]])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0])
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
+
+ test(15, "invalid", ['--user-config="%s"' % configFileNames[0]])
+ t.expect_output_lines(implicitConfigLoadMessage, False)
+ t.expect_output_lines(explicitConfigLoadMessage)
+ t.expect_output_lines(disabledConfigLoadMessage, False)
+ t.expect_output_lines(testMessage % configFileNames[0])
+ t.expect_output_lines(testMessage % configFileNames[1], False)
+ t.expect_output_lines(testMessage % configFileNames[2], False)
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
+#
+# Private interface.
+#
+###############################################################################
+
+def _canSetEmptyEnvironmentVariable():
+ """
+ Unfortunately different OSs (and possibly Python implementations as well)
+ have different interpretations of what it means to set an evironment
+ variable to an empty string. Some (e.g. Windows) interpret it as unsetting
+ the variable and some (e.g. AIX or Darwin) actually set it to an empty
+ string.
+
+ """
+ dummyName = "UGNABUNGA_FOO_BAR_BAZ_FEE_FAE_FOU_FAM"
+ original = os.environ.get(dummyName)
+ _env_set(dummyName, "")
+ result = _getExternalEnv(dummyName) == ""
+ _env_set(dummyName, original)
+ return result
+
+
+def _env_del(name):
+ """
+ Unsets the given environment variable if it is currently set.
+
+ Note that we can not use os.environ.pop() or os.environ.clear() here
+ since prior to Python 2.6 these functions did not remove the actual
+ environment variable by calling os.unsetenv().
+
+ """
+ try:
+ del os.environ[name]
+ except KeyError:
+ pass
+
+
+def _env_set(name, value):
+ """
+ Sets the given environment variable value or unsets it, if the value is
+ None.
+
+ """
+ if value is None:
+ _env_del(name)
+ else:
+ os.environ[name] = value
+
+
+def _getExternalEnv(name):
+ toolsetName = "__myDummyToolset__"
+
+ t = BoostBuild.Tester(["toolset=%s" % toolsetName], pass_toolset=False,
+ use_test_config=False)
+ try:
+ # Prepare a dummy toolset so we do not get errors in case the default
+ # one is not found.
+ t.write(toolsetName + ".jam", """\
+import feature ;
+feature.extend toolset : %s ;
+rule init ( ) { }
+""" % toolsetName)
+
+ # Python version of the same dummy toolset.
+ t.write(toolsetName + ".py", """\
+from b2.build import feature
+feature.extend('toolset', ['%s'])
+def init(): pass
+""" % toolsetName)
+
+ t.write("jamroot.jam", """\
+import os ;
+local names = [ MATCH ^---var-name---=(.*) : [ modules.peek : ARGV ] ] ;
+for x in $(names)
+{
+ value = [ os.environ $(x) ] ;
+ ECHO "###" $(x): '$(value)' "###" ;
+}
+""")
+
+ t.run_build_system(["---var-name---=%s" % name])
+ m = re.search("^### %s: '(.*)' ###$" % name, t.stdout(), re.MULTILINE)
+ if m:
+ return m.group(1)
+ finally:
+ t.cleanup()
+
+
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
+
+canSetEmptyEnvironmentVariable = _canSetEmptyEnvironmentVariable()
 
 test_user_configuration()

Modified: branches/release/tools/build/v2/test/copy_time.py
==============================================================================
--- branches/release/tools/build/v2/test/copy_time.py (original)
+++ branches/release/tools/build/v2/test/copy_time.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,21 +1,19 @@
 #!/usr/bin/python
 #
-# Copyright (c) 2008
-# Steven Watanabe
+# Copyright (c) 2008 Steven Watanabe
 #
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
+# 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)
 
-# Test that the common.copy rule set the modification
-# date of the new file the current time.
+# Test that the common.copy rule set the modification date of the new file to
+# the current time.
 
 import BoostBuild
 
-tester = BoostBuild.Tester()
+tester = BoostBuild.Tester(use_test_config=False)
 
-tester.write("test1.cpp", """
-#include <iostream>
+tester.write("test1.cpp", """\
 template<bool, int M, class Next>
 struct time_waster {
     typedef typename time_waster<true, M-1, time_waster>::type type1;
@@ -30,8 +28,7 @@
 int f() { return 0; }
 """)
 
-tester.write("test2.cpp", """
-#include <iostream>
+tester.write("test2.cpp", """\
 template<bool, int M, class Next>
 struct time_waster {
     typedef typename time_waster<true, M-1, time_waster>::type type1;
@@ -46,14 +43,13 @@
 int g() { return 0; }
 """)
 
-tester.write("jamroot.jam", """
+tester.write("jamroot.jam", """\
 obj test2 : test2.cpp ;
 obj test1 : test1.cpp : <dependency>test2 ;
 install test2i : test2 : <dependency>test1 ;
 """)
 
 tester.run_build_system()
-
 tester.expect_addition("bin/$toolset/debug/test2.obj")
 tester.expect_addition("bin/$toolset/debug/test1.obj")
 tester.expect_addition("test2i/test2.obj")
@@ -61,16 +57,13 @@
 
 test2src = tester.read("test2i/test2.obj")
 test2dest = tester.read("bin/$toolset/debug/test2.obj")
-
 if test2src != test2dest:
- BoostBuild.annotation("failure", "The object file was not copied correctly")
+ BoostBuild.annotation("failure", "The object file was not copied "
+ "correctly")
     tester.fail_test(1)
 
-del test2src
-del test2dest
-
-tester.run_build_system("-d1")
-tester.expect_output_line("common.copy*", expected_to_exist=False)
+tester.run_build_system(["-d1"])
+tester.expect_output_lines("common.copy*", False)
 tester.expect_nothing_more()
 
 tester.cleanup()

Modified: branches/release/tools/build/v2/test/core-language/test.jam
==============================================================================
--- branches/release/tools/build/v2/test/core-language/test.jam (original)
+++ branches/release/tools/build/v2/test/core-language/test.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -75,6 +75,7 @@
 check-equal var-LU : $(v4:LU) : STRING/WITH/MIXED/CASE ;
 check-equal var-slashes : $(v5:T) : path/with/backslashes ;
 check-equal var-grist : $(v6:G) : <grist> ;
+check-equal var-grist-none : $(v1:G) : "" "" "" ;
 check-equal var-base : $(v6:B) : path ;
 check-equal var-suffix : $(v6:S) : .txt ;
 check-equal var-dir : $(v6:D) : generic ;
@@ -120,7 +121,7 @@
 
     local cyg-grist = <grist>$(cyg1) ;
     check-equal cygwin-grist : $(cyg-grist:W) : <grist>\\cygdrive\\c\\path1.txt ;
-
+
     check-equal cygwin-WU : $(cyg2:WU) : $(cyg-root:U)\\BIN\\BASH ;
     # behavior change: L now consistently applied after W.
     # used to affect all except the drive letter.
@@ -234,7 +235,7 @@
 x = reset ;
 rule reset-x ( new-value )
 {
- x = $(new-value) ;
+ x = $(new-value) ;
 }
 $(x)-x bar ; # invokes reset-x...
 check-equal rule-reset : $(x) : bar ; # which changes x
@@ -249,6 +250,27 @@
 $(x)-x [ mark-order r1 : [ reset-x reset ] ] : [ mark-order r2 ] ;
 check-order rule-order : r1 r2 ;
 
+# Cases that look like member calls
+rule looks.like-a-member ( args * )
+{
+ return $(args) ;
+}
+
+rule call-non-member ( rule + )
+{
+ return [ $(rule).like-a-member ] ;
+}
+
+rule call-non-member-with-args ( rule + )
+{
+ return [ $(rule).like-a-member a2 ] ;
+}
+
+check-equal rule-non-member : [ call-non-member looks ] : ;
+#check-equal rule-non-member-a1 : [ call-non-member looks a1 ] : looks.a1 ;
+check-equal rule-non-member-args : [ call-non-member-with-args looks ] : a2 ;
+#check-equal rule-non-member-args-a1 : [ call-non-member-with-args looks a1 ] : looks.a1 a2 ;
+
 }
 
 # Check append
@@ -713,7 +735,7 @@
     check-equal module-var-not-root : $(var1) : root-module-var ;
 
     check-equal module-rulenames : [ RULENAMES my_module ] : get ;
-
+
     IMPORT_MODULE my_module ;
     check-equal module-rule-import-module : [ my_module.get ] : module-var ;
 
@@ -1293,16 +1315,41 @@
 if $(NT)
 {
     local sound = "Beep" "ExtendedSounds" ;
- local r1 = [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : values ] ;
+ local r1 = [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" :
+ values ] ;
     check-equal w32_getregnames : $(sound:L) : $(r1:L) ;
     local r2 = [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ;
     check-equal w32_getregnames : $(sound:L) : $(r2:L) ;
 
+ # Some Windows platforms may have additional keys under
+ # 'CurrentControlSet' which we then remove here so they would not be
+ # reported as errors by our test.
+ local rule remove-policies ( param * )
+ {
+ local found ;
+ local r ;
+ for local x in $(param:L)
+ {
+ if ! x in $(found) &&
+ $(x) in "addservices" "policies" "deleted device ids"
+ {
+ found += $(x) ;
+ }
+ else
+ {
+ r += $(x) ;
+ }
+ }
+ return $(r) ;
+ }
     local CurrentControlSet = "Control" "Enum" "Hardware Profiles" "Services" ;
- local r3 = [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" : subkeys ] ;
- check-equal w32_getregnames : $(CurrentControlSet:L) : $(r3:L) ;
+ local r3 = [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet"
+ : subkeys ] ;
+ check-equal w32_getregnames : $(CurrentControlSet:L) : [ remove-policies
+ $(r3:L) ] ;
     local r4 = [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ;
- check-equal w32_getregnames : $(CurrentControlSet:L) : $(r4:L) ;
+ check-equal w32_getregnames : $(CurrentControlSet:L) : [ remove-policies
+ $(r4:L) ] ;
 }
 
 }
@@ -1333,7 +1380,7 @@
 
 # Check that a matched subst works
 check-equal subst-match : [ SUBST "ddd" "d+" x ] : x ;
-
+
 # Check that we can get multiple substitutions from a single invocation
 check-equal subst-multiple : [ SUBST "x/y/z" "([^/]*)/([^/]*).*" "\\1" $2 "\\1-\\2" ] : x y x-y ;
 

Copied: branches/release/tools/build/v2/test/core_action_output.py (from r79124, /trunk/tools/build/v2/test/core_action_output.py)
==============================================================================
--- /trunk/tools/build/v2/test/core_action_output.py (original)
+++ branches/release/tools/build/v2/test/core_action_output.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,17 +2,18 @@
 
 # Copyright 2012. Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Test correct "-p" option handling.
 
 import BoostBuild
 
-t = BoostBuild.Tester("-d1", pass_d0=False, pass_toolset=False)
+t = BoostBuild.Tester(["-d1"], pass_d0=False, pass_toolset=False)
 
 t.write("file.jam", """\
-prefix = "echo \"" ;
-suffix = "\"" ;
+prefix = "echo \\"" ;
+suffix = "\\"" ;
 if $(NT)
 {
     prefix = "(echo " ;
@@ -28,34 +29,34 @@
 go all ;
 """)
 
-t.run_build_system("-ffile.jam -sXXX=1", stderr="")
-t.expect_output_line("{{{ 1 }}}")
-t.expect_output_line("stdout")
-t.expect_output_line("stderr")
+t.run_build_system(["-ffile.jam", "-sXXX=1"], stderr="")
+t.expect_output_lines("{{{ 1 }}}")
+t.expect_output_lines("stdout")
+t.expect_output_lines("stderr")
 t.expect_nothing_more()
 
-t.run_build_system("-ffile.jam -sXXX=2 -p0", stderr="")
-t.expect_output_line("{{{ 2 }}}")
-t.expect_output_line("stdout")
-t.expect_output_line("stderr")
+t.run_build_system(["-ffile.jam", "-sXXX=2", "-p0"], stderr="")
+t.expect_output_lines("{{{ 2 }}}")
+t.expect_output_lines("stdout")
+t.expect_output_lines("stderr")
 t.expect_nothing_more()
 
-t.run_build_system("-ffile.jam -sXXX=3 -p1", stderr="")
-t.expect_output_line("{{{ 3 }}}")
-t.expect_output_line("stdout")
-t.expect_output_line("stderr*", False)
+t.run_build_system(["-ffile.jam", "-sXXX=3", "-p1"], stderr="")
+t.expect_output_lines("{{{ 3 }}}")
+t.expect_output_lines("stdout")
+t.expect_output_lines("stderr*", False)
 t.expect_nothing_more()
 
-t.run_build_system("-ffile.jam -sXXX=4 -p2", stderr="stderr\n")
-t.expect_output_line("{{{ 4 }}}")
-t.expect_output_line("stdout*", False)
-t.expect_output_line("stderr*", False)
+t.run_build_system(["-ffile.jam", "-sXXX=4", "-p2"], stderr="stderr\n")
+t.expect_output_lines("{{{ 4 }}}")
+t.expect_output_lines("stdout*", False)
+t.expect_output_lines("stderr*", False)
 t.expect_nothing_more()
 
-t.run_build_system("-ffile.jam -sXXX=5 -p3", stderr="stderr\n")
-t.expect_output_line("{{{ 5 }}}")
-t.expect_output_line("stdout")
-t.expect_output_line("stderr", False)
+t.run_build_system(["-ffile.jam", "-sXXX=5", "-p3"], stderr="stderr\n")
+t.expect_output_lines("{{{ 5 }}}")
+t.expect_output_lines("stdout")
+t.expect_output_lines("stderr*", False)
 t.expect_nothing_more()
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_action_status.py
==============================================================================
--- branches/release/tools/build/v2/test/core_action_status.py (original)
+++ branches/release/tools/build/v2/test/core_action_status.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,26 +2,26 @@
 
 # Copyright 2007 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
 
-t.write("file.jam", """
- actions quietly .a. { $(ACTION) }
+t.write("file.jam", """\
+actions quietly .a. { $(ACTION) }
 
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- DEPENDS all : subtest_a ;
+rule .a.
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+NOTFILE subtest ;
+.a. subtest_a : subtest ;
+DEPENDS all : subtest_a ;
 """)
 
-t.run_build_system("-ffile.jam -sACTION=invalid", status=1)
+t.run_build_system(["-ffile.jam", "-sACTION=invalid"], status=1)
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_actions_quietly.py
==============================================================================
--- branches/release/tools/build/v2/test/core_actions_quietly.py (original)
+++ branches/release/tools/build/v2/test/core_actions_quietly.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,40 +2,41 @@
 
 # Copyright 2007 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
 
-t.write("file.jam", """
- actions quietly .a.
- {
+t.write("file.jam", """\
+actions quietly .a.
+{
 echo [$(<:B)] 0
 echo [$(<:B)] 1
 echo [$(<:B)] 2
- }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- .a. subtest_b : subtest ;
- DEPENDS all : subtest_a subtest_b ;
+}
+
+rule .a.
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+NOTFILE subtest ;
+.a. subtest_a : subtest ;
+.a. subtest_b : subtest ;
+DEPENDS all : subtest_a subtest_b ;
 """)
 
-t.run_build_system("-ffile.jam -d2", stdout="""...found 4 targets...
+t.run_build_system(["-ffile.jam", "-d2"], stdout="""\
+...found 4 targets...
 ...updating 2 targets...
 .a. subtest_a
 
 echo [subtest_a] 0
 echo [subtest_a] 1
 echo [subtest_a] 2
-
+
 [subtest_a] 0
 [subtest_a] 1
 [subtest_a] 2
@@ -44,14 +45,15 @@
 echo [subtest_b] 0
 echo [subtest_b] 1
 echo [subtest_b] 2
-
+
 [subtest_b] 0
 [subtest_b] 1
 [subtest_b] 2
 ...updated 2 targets...
 """)
 
-t.run_build_system("-ffile.jam -d1", stdout="""...found 4 targets...
+t.run_build_system(["-ffile.jam", "-d1"], stdout="""\
+...found 4 targets...
 ...updating 2 targets...
 ...updated 2 targets...
 """)

Modified: branches/release/tools/build/v2/test/core_arguments.py
==============================================================================
--- branches/release/tools/build/v2/test/core_arguments.py (original)
+++ branches/release/tools/build/v2/test/core_arguments.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,16 +1,40 @@
 #!/usr/bin/python
 
-# Copyright 2001 Dave Abrahams
+# Copyright 2001 Dave Abrahams
 # Copyright 2011 Steven Watanabe
-# 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)
+# 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 BoostBuild
-import os
+
+
+def simple_args(start, finish):
+ return " : ".join("%d" % x for x in xrange(start, finish + 1))
+
+
+def test(t, type, input, output, status=0):
+ code = ["include echo_args.jam ; echo_%s" % type]
+ if input: code.append(input)
+ code.append(";")
+ t.write("file.jam", " ".join(code))
+ t.run_build_system(["-ffile.jam"], status=status)
+ t.expect_output_lines(output);
+
+
+def test_args(t, *args, **kwargs):
+ test(t, "args", *args, **kwargs)
+
+
+def test_varargs(t, *args, **kwargs):
+ test(t, "varargs", *args, **kwargs)
+
 
 t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
-t.write("echo_args.jam", """
+t.write("echo_args.jam", """\
+NOCARE all ;
+
 rule echo_args ( a b ? c ? : d + : e * )
 {
     ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) ;
@@ -19,91 +43,61 @@
 rule echo_varargs ( a b ? c ? : d + : e * : * )
 {
     ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e)
- ": rest= "$(4[1]) $(4[2])
- ": "$(5[1]) $(5[2])
- ": "$(6[1]) $(6[2])
- ": "$(7[1]) $(7[2])
- ": "$(8[1]) $(8[2])
- ": "$(9[1]) $(9[2]) ;
+ ": rest= "$(4[1]) $(4[2-])
+ ": "$(5[1]) $(5[2-]) ": "$(6[1]) $(6[2-]) ": "$(7[1]) $(7[2-])
+ ": "$(8[1]) $(8[2-]) ": "$(9[1]) $(9[2-]) ": "$(10[1]) $(10[2-])
+ ": "$(11[1]) $(11[2-]) ": "$(12[1]) $(12[2-]) ": "$(13[1]) $(13[2-])
+ ": "$(14[1]) $(14[2-]) ": "$(15[1]) $(15[2-]) ": "$(16[1]) $(16[2-])
+ ": "$(17[1]) $(17[2-]) ": "$(18[1]) $(18[2-]) ": "$(19[1]) $(19[2-])
+ ": "$(20[1]) $(20[2-]) ": "$(21[1]) $(21[2-]) ": "$(22[1]) $(22[2-])
+ ": "$(23[1]) $(23[2-]) ": "$(24[1]) $(24[2-]) ": "$(25[1]) $(25[2-]) ;
 }
 """)
 
-t.write("file.jam", "include echo_args.jam ; echo_args ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("* missing argument a");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 2 : 3 : 4 : 5 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("* extra argument 5");
-
-t.write("file.jam", "include echo_args.jam ; echo_args a b c1 c2 : d ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("* extra argument c2");
+test_args(t, "", "* missing argument a", status=1)
+test_args(t, "1 2 : 3 : 4 : 5", "* extra argument 5", status=1)
+test_args(t, "a b c1 c2 : d", "* extra argument c2", status=1)
 
 # Check modifier '?'
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 2 3 : 4 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= 2 c= 3 : d= 4 : e=");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 2 : 3 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= 2 c= : d= 3 : e=");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e=");
+test_args(t, "1 2 3 : 4", "a= 1 b= 2 c= 3 : d= 4 : e=")
+test_args(t, "1 2 : 3", "a= 1 b= 2 c= : d= 3 : e=")
+test_args(t, "1 2 : 3", "a= 1 b= 2 c= : d= 3 : e=")
+test_args(t, "1 : 2", "a= 1 b= c= : d= 2 : e=")
 
 # Check modifier '+'
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("* missing argument d");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 3 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 3 : e=");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 3 4 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 3 4 : e=");
+test_args(t, "1", "* missing argument d", status=1)
+test_args(t, "1 : 2 3", "a= 1 b= c= : d= 2 3 : e=")
+test_args(t, "1 : 2 3 4", "a= 1 b= c= : d= 2 3 4 : e=")
 
 # Check modifier '*'
+test_args(t, "1 : 2 : 3", "a= 1 b= c= : d= 2 : e= 3")
+test_args(t, "1 : 2 : 3 4", "a= 1 b= c= : d= 2 : e= 3 4")
+test_args(t, "1 : 2 : 3 4 5", "a= 1 b= c= : d= 2 : e= 3 4 5")
 
-t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 : 3 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 : 3 4 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4");
-
-t.write("file.jam", "include echo_args.jam ; echo_args 1 : 2 : 3 4 5 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5");
-
-#
 # Check varargs
-#
-
-t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5");
-
-t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6");
-
-t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 7 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7");
-
-t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 7 : 8 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8");
-
-t.write("file.jam", "include echo_args.jam ; echo_varargs 1 : 2 : 3 4 5 : 6 7 : 8 : 9 ;")
-t.run_build_system("-ffile.jam", status=1)
-t.expect_output_line("a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : 9");
+test_varargs(t, "1 : 2 : 3 4 5", "a= 1 b= c= : d= 2 : e= 3 4 5")
+test_varargs(t, "1 : 2 : 3 4 5 : 6", "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6")
+test_varargs(t, "1 : 2 : 3 4 5 : 6 7",
+ "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7")
+test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8",
+ "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8")
+test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8 : 9",
+ "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : 9")
+test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : "
+ "16 : 17 : 18 : 19a 19b", "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : "
+ "9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19a 19b")
+test_varargs(t, "1 : 2 : 3 4 5 : 6 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : "
+ "16 : 17 : 18 : 19a 19b 19c : 20", "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= "
+ "6 7 : 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19a 19b 19c : "
+ "20")
+
+# Check varargs upper limit
+expected = "a= 1 b= c= : d= 2 : e= 3 : rest= " + simple_args(4, 19)
+test_varargs(t, simple_args(1, 19), expected)
+test_varargs(t, simple_args(1, 19) + " 19b 19c 19d", expected + " 19b 19c 19d")
+test_varargs(t, simple_args(1, 19) + " 19b 19c 19d : 20", expected + " 19b "
+ "19c 19d")
+test_varargs(t, simple_args(1, 20), expected)
+test_varargs(t, simple_args(1, 50), expected)
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_at_file.py
==============================================================================
--- branches/release/tools/build/v2/test/core_at_file.py (original)
+++ branches/release/tools/build/v2/test/core_at_file.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,75 +1,63 @@
 #!/usr/bin/python
 
 # Copyright 2011 Steven Watanabe
-# 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)
+# 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 BoostBuild
-import os
 
-t = BoostBuild.Tester(pass_toolset=0)
+t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0)
 
-t.write("file.jam", """
+t.write("file.jam", """\
 name = n1 n2 ;
 contents = M1 M2 ;
 EXIT file: "@(o$(name) .txt:E= test -D$(contents))" : 0 ;
 """)
 
-t.run_build_system("-ffile.jam")
-t.expect_output_line("file: on1 on2 .txt");
+t.run_build_system()
+t.expect_output_lines("file: on1 on2 .txt");
 t.expect_addition("on1 on2 .txt")
 t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True)
 
 t.rm(".")
 
-t.write("file.jam", """
+t.write("file.jam", """\
 name = n1 n2 ;
 contents = M1 M2 ;
-actions run {
-echo file: "@(o$(name) .txt:E= test -D$(contents))"
-}
-
+actions run { echo file: "@(o$(name) .txt:E= test -D$(contents))" }
 run all ;
-
 """)
 
-t.run_build_system("-ffile.jam -d2")
-t.expect_output_line('echo file: "on1 on2 .txt"');
+t.run_build_system(["-d2"])
+t.expect_output_lines(' echo file: "on1 on2 .txt" ');
 t.expect_addition("on1 on2 .txt")
 t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True)
 
 t.rm(".")
 
-t.write("file.jam", """
+t.write("file.jam", """\
 name = n1 n2 ;
 contents = M1 M2 ;
 file = "@($(STDOUT):E= test -D$(contents)\n)" ;
-
-actions run {
-$(file)
-}
-
+actions run { $(file) }
 run all ;
 """)
 
-t.run_build_system("-ffile.jam -d1")
-t.expect_output_line(" test -DM1 -DM2")
+t.run_build_system(["-d1"])
+t.expect_output_lines(" test -DM1 -DM2")
 
 t.rm(".")
 
-t.write("file.jam", """
+t.write("file.jam", """\
 name = n1 n2 ;
 contents = M1 M2 ;
-actions run {
-@($(STDOUT):E= test -D$(contents)\n)
-}
-
+actions run { @($(STDOUT):E= test -D$(contents)\n) }
 run all ;
-
 """)
 
-t.run_build_system("-ffile.jam -d1")
-t.expect_output_line(" test -DM1 -DM2")
+t.run_build_system(["-d1"])
+t.expect_output_lines(" test -DM1 -DM2")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_bindrule.py
==============================================================================
--- branches/release/tools/build/v2/test/core_bindrule.py (original)
+++ branches/release/tools/build/v2/test/core_bindrule.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,21 +12,18 @@
 
 t.write("subdir1/file-to-bind", "# This file intentionally left blank")
 
-t.write("file.jam", """
+t.write("file.jam", """\
 rule do-nothing ( target : source )
 {
     DEPENDS $(target) : $(source) ;
 }
-actions quietly do-nothing
-{
-}
+actions quietly do-nothing { }
 
 # Make a non-file target which depends on a file that exists
 NOTFILE fake-target ;
 SEARCH on file-to-bind = subdir1 ;
 
-do-nothing fake-target
- : file-to-bind ;
+do-nothing fake-target : file-to-bind ;
 
 # Set jam up to call our bind-rule
 BINDRULE = bind-rule ;
@@ -39,7 +36,8 @@
 DEPENDS all : fake-target ;
 """)
 
-t.run_build_system("-ffile.jam", stdout="""found: all at all
+t.run_build_system(["-ffile.jam"], stdout="""\
+found: all at all
 found: file-to-bind at subdir1%sfile-to-bind
 ...found 3 targets...
 """ % os.sep)

Modified: branches/release/tools/build/v2/test/core_d12.py
==============================================================================
--- branches/release/tools/build/v2/test/core_d12.py (original)
+++ branches/release/tools/build/v2/test/core_d12.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,15 +2,16 @@
 
 # Copyright 2002, 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # This tests correct handling of "-d1" and "-d2" options.
 
 import BoostBuild
 
-t = BoostBuild.Tester(pass_toolset=0)
+t = BoostBuild.Tester(["-ffile.jam"], pass_d0=False, pass_toolset=0)
 
-t.write("file.jam", """
+t.write("file.jam", """\
 actions a { }
 actions quietly b { }
 ALWAYS all ;
@@ -18,18 +19,14 @@
 b all ;
 """)
 
-t.run_build_system("-ffile.jam -d0", stdout="")
+t.run_build_system(["-d0"], stdout="")
 
-t.run_build_system("-ffile.jam -d1", stdout=
-"""...found 1 target...
-...updating 1 target...
-a all
-...updated 1 target...
-""")
-
-t.run_build_system("-ffile.jam -d2")
-
-t.fail_test(t.stdout().find("a all") == -1)
-t.fail_test(t.stdout().find("b all") == -1)
+t.run_build_system(["-d1"])
+t.expect_output_lines("a all")
+t.expect_output_lines("b all", False)
+
+t.run_build_system(["-d2"])
+t.expect_output_lines("a all")
+t.expect_output_lines("b all")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_delete_module.py
==============================================================================
--- branches/release/tools/build/v2/test/core_delete_module.py (original)
+++ branches/release/tools/build/v2/test/core_delete_module.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -47,5 +47,5 @@
 NOTFILE xx ;
 """)
 
-t.run_build_system("-ffile.jam", status=0)
+t.run_build_system(["-ffile.jam"], status=0)
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_import_module.py
==============================================================================
--- branches/release/tools/build/v2/test/core_import_module.py (original)
+++ branches/release/tools/build/v2/test/core_import_module.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,13 +2,14 @@
 
 # Copyright 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
 
-t.write("code", """
+t.write("code", """\
 module a
 {
     rule r1 ( )
@@ -70,7 +71,8 @@
 do-nothing all ;
 """)
 
-t.run_build_system("-fcode", stdout="""R1
+t.run_build_system(["-fcode"], stdout="""\
+R1
 R2
 L1
 A.L1

Modified: branches/release/tools/build/v2/test/core_language.py
==============================================================================
--- branches/release/tools/build/v2/test/core_language.py (original)
+++ branches/release/tools/build/v2/test/core_language.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,8 +7,6 @@
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
-
 t.set_tree("core-language")
-t.run_build_system(extra_args="-ftest.jam")
-
+t.run_build_system(["-ftest.jam"])
 t.cleanup()

Copied: branches/release/tools/build/v2/test/core_nt_cmd_line.py (from r79097, /trunk/tools/build/v2/test/core_nt_cmd_line.py)
==============================================================================
--- /trunk/tools/build/v2/test/core_nt_cmd_line.py (original)
+++ branches/release/tools/build/v2/test/core_nt_cmd_line.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -3,7 +3,8 @@
 # Copyright 2001 Dave Abrahams
 # Copyright 2011 Steven Watanabe
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Tests Windows command line construction.
 #
@@ -34,25 +35,39 @@
     return " ".join(result)
 
 
-# Boost Jam currently does not allow preparing actions with completly empty
-# content as it always requires at least a single whitespace after the opening
-# brace in order to satisfy.
+# Boost Jam currently does not allow preparing actions with completely empty
+# content and always requires at least a single whitespace after the opening
+# brace in order to satisfy its Boost Jam language grammar rules.
 def test_raw_empty():
- t = BoostBuild.Tester("-d2 -d+4", pass_d0=False, pass_toolset=0,
+ whitespace_in = " \n\n\r\r\v\v\t\t \t \r\r \n\n"
+
+ # We tell the testing system to read its child process output as raw
+ # binary data but the bjam process we run will read its input file and
+ # write out its output as text, i.e. convert all of our "\r\n" sequences to
+ # "\n" on input and all of its "\n" characters back to "\r\n" on output.
+ # This means that any lone "\n" input characters not preceded by "\r" will
+ # get an extra "\r" added in front of it on output.
+ whitespace_out = whitespace_in.replace("\r\n", "\n").replace("\n", "\r\n")
+
+ t = BoostBuild.Tester(["-d2", "-d+4"], pass_d0=False, pass_toolset=0,
         use_test_config=False)
     t.write("file.jam", """\
-actions do_empty { %s}
+actions do_empty {%s}
 JAMSHELL = %% ;
 do_empty all ;
-""" % (" \n\n\r\r\v\v\t\t \t \r\r \n\n"))
- t.run_build_system("-ffile.jam")
- t.expect_output_line("do_empty*", False)
- t.expect_output_line("Executing raw command directly", False)
+""" % (whitespace_in))
+ t.run_build_system(["-ffile.jam"], universal_newlines=False)
+ t.expect_output_lines("do_empty all")
+ t.expect_output_lines("Executing raw command directly", False)
+ if "\r\n%s\r\n" % whitespace_out not in t.stdout():
+ BoostBuild.annotation("failure", "Whitespace action content not found "
+ "on stdout.")
+ t.fail_test(1, dump_difference=False)
     t.cleanup()
 
 
 def test_raw_nt(n=None, error=False):
- t = BoostBuild.Tester("-d1 -d+4", pass_d0=False, pass_toolset=0,
+ t = BoostBuild.Tester(["-d1", "-d+4"], pass_d0=False, pass_toolset=0,
         use_test_config=False)
 
     cmd_prefix = "%s -c \"print('XXX: " % executable
@@ -91,14 +106,19 @@
 JAMSHELL = %% ;
 do_echo all ;
 """ % (cmd_prefix, string_of_length(data_length), cmd_suffix))
- t.run_build_system("-ffile.jam", status=1 if error else 0)
     if error:
- t.expect_output_line("Executing raw command directly", False)
- t.expect_output_line("do_echo action is too long (%d, max 32766):" % n)
- t.expect_output_line("XXX: *", False)
+ expected_status = 1
     else:
- t.expect_output_line("Executing raw command directly")
- t.expect_output_line("do_echo action is too long*", False)
+ expected_status = 0
+ t.run_build_system(["-ffile.jam"], status=expected_status)
+ if error:
+ t.expect_output_lines("Executing raw command directly", False)
+ t.expect_output_lines("do_echo action is too long (%d, max 32766):" % n
+ )
+ t.expect_output_lines("XXX: *", False)
+ else:
+ t.expect_output_lines("Executing raw command directly")
+ t.expect_output_lines("do_echo action is too long*", False)
 
         m = re.search("^XXX: (.*)$", t.stdout(), re.MULTILINE)
         if not m:
@@ -115,7 +135,7 @@
 
 
 def test_raw_to_shell_fallback_nt():
- t = BoostBuild.Tester("-d1 -d+4", pass_d0=False, pass_toolset=0,
+ t = BoostBuild.Tester(["-d1", "-d+4"], pass_d0=False, pass_toolset=0,
         use_test_config=False)
 
     cmd_prefix = '%s -c print(' % executable
@@ -132,12 +152,12 @@
 JAMSHELL = % ;
 do_multiline all ;
 """)
- t.run_build_system("-ffile_multiline.jam")
- t.expect_output_line("do_multiline all")
- t.expect_output_line("one")
- t.expect_output_line("two")
- t.expect_output_line("Executing raw command directly", False)
- t.expect_output_line("Executing using a command file and the shell: "
+ t.run_build_system(["-ffile_multiline.jam"])
+ t.expect_output_lines("do_multiline all")
+ t.expect_output_lines("one")
+ t.expect_output_lines("two")
+ t.expect_output_lines("Executing raw command directly", False)
+ t.expect_output_lines("Executing using a command file and the shell: "
         "cmd.exe /Q/C")
 
     t.write("file_redirect.jam", """\
@@ -145,25 +165,28 @@
 JAMSHELL = % ;
 do_redirect all ;
 """)
- t.run_build_system("-ffile_redirect.jam")
- t.expect_output_line("do_redirect all")
- t.expect_output_line("one", False)
- t.expect_output_line("Executing raw command directly", False)
- t.expect_output_line("Executing using a command file and the shell: "
+ t.run_build_system(["-ffile_redirect.jam"])
+ t.expect_output_lines("do_redirect all")
+ t.expect_output_lines("one", False)
+ t.expect_output_lines("Executing raw command directly", False)
+ t.expect_output_lines("Executing using a command file and the shell: "
         "cmd.exe /Q/C")
     t.expect_addition("two.txt")
 
     t.write("file_pipe.jam", """\
-actions do_pipe { echo one | echo two }
+actions do_pipe
+{
+ echo one | echo two
+}
 JAMSHELL = % ;
 do_pipe all ;
 """)
- t.run_build_system("-ffile_pipe.jam")
- t.expect_output_line("do_pipe all")
- t.expect_output_line("one", False)
- t.expect_output_line("two")
- t.expect_output_line("Executing raw command directly", False)
- t.expect_output_line("Executing using a command file and the shell: "
+ t.run_build_system(["-ffile_pipe.jam"])
+ t.expect_output_lines("do_pipe all")
+ t.expect_output_lines("one*", False)
+ t.expect_output_lines("two")
+ t.expect_output_lines("Executing raw command directly", False)
+ t.expect_output_lines("Executing using a command file and the shell: "
         "cmd.exe /Q/C")
 
     t.write("file_single_quoted.jam", """\
@@ -171,11 +194,11 @@
 JAMSHELL = %% ;
 do_single_quoted all ;
 """ % (cmd_prefix, cmd_suffix))
- t.run_build_system("-ffile_single_quoted.jam")
- t.expect_output_line("do_single_quoted all")
- t.expect_output_line("5>10")
- t.expect_output_line("Executing raw command directly")
- t.expect_output_line("Executing using a command file and the shell: "
+ t.run_build_system(["-ffile_single_quoted.jam"])
+ t.expect_output_lines("do_single_quoted all")
+ t.expect_output_lines("5>10")
+ t.expect_output_lines("Executing raw command directly")
+ t.expect_output_lines("Executing using a command file and the shell: "
         "cmd.exe /Q/C", False)
     t.expect_nothing_more()
 
@@ -184,14 +207,14 @@
 JAMSHELL = %% ;
 do_double_quoted all ;
 """ % (cmd_prefix, cmd_suffix))
- t.run_build_system("-ffile_double_quoted.jam")
- t.expect_output_line("do_double_quoted all")
+ t.run_build_system(["-ffile_double_quoted.jam"])
+ t.expect_output_lines("do_double_quoted all")
     # The difference between this example and the similar previous one using
     # single instead of double quotes stems from how the used Python executable
     # parses the command-line string received from Windows.
- t.expect_output_line("False")
- t.expect_output_line("Executing raw command directly")
- t.expect_output_line("Executing using a command file and the shell: "
+ t.expect_output_lines("False")
+ t.expect_output_lines("Executing raw command directly")
+ t.expect_output_lines("Executing using a command file and the shell: "
         "cmd.exe /Q/C", False)
     t.expect_nothing_more()
 
@@ -200,11 +223,11 @@
 JAMSHELL = %% ;
 do_escaped_quote all ;
 """ % (cmd_prefix, cmd_suffix))
- t.run_build_system("-ffile_escaped_quote.jam")
- t.expect_output_line("do_escaped_quote all")
- t.expect_output_line("5>10")
- t.expect_output_line("Executing raw command directly", False)
- t.expect_output_line("Executing using a command file and the shell: "
+ t.run_build_system(["-ffile_escaped_quote.jam"])
+ t.expect_output_lines("do_escaped_quote all")
+ t.expect_output_lines("5>10")
+ t.expect_output_lines("Executing raw command directly", False)
+ t.expect_output_lines("Executing using a command file and the shell: "
         "cmd.exe /Q/C")
     t.expect_nothing_more()
 

Deleted: branches/release/tools/build/v2/test/core_nt_line_length.py
==============================================================================
--- branches/release/tools/build/v2/test/core_nt_line_length.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
+++ (empty file)
@@ -1,52 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2001 Dave Abrahams
-# Copyright 2011 Steven Watanabe
-# Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-import BoostBuild
-import os
-
-t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
-
-t.write("file.jam", """
-if $(NT)
-{
- #
- # Build a really long commandline. (> 10K characters).
- #
- ten = 0 1 2 3 4 5 6 7 8 9 ;
- 1x7chars = 0_____ ;
- # add a digit and multiply by 10
- 10x8chars = $(ten)$(1x7chars) ;
- # add a digit to each of 10 strings and multiply by 10
- 100x9chars = $(ten)$(10x8chars) ;
- # add a digit to each of 100 strings and multiply by 10
- 1000x10chars = $(ten)$(100x9chars) ;
-
- #
- # Cause line_length_test to be built
- #
- actions do_echo
- {
- echo $(text)
- }
-
- 400x10chars = $(ten[1-4])$(100x9chars) ;
-
- text on line_length_test = $(400x10chars) 40$(10x8chars[1-9]) 01234 ;
- text on line_length_test = $(1000x10chars) $(1000x10chars) ;
- JAMSHELL on line_length_test = % ;
- DEPENDS all : line_length_test ;
-
- do_echo line_length_test ;
-}
-else
-{
- NOCARE all ;
-}
-""")
-t.run_build_system("-ffile.jam")
-
-t.cleanup()

Modified: branches/release/tools/build/v2/test/core_option_d2.py
==============================================================================
--- branches/release/tools/build/v2/test/core_option_d2.py (original)
+++ branches/release/tools/build/v2/test/core_option_d2.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,45 +2,41 @@
 
 # Copyright 2007 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
-t.write("sleep.bat","""@setlocal
-_at_echo off
-timeout /T %1 /NOBREAK >nul
-""")
-
-t.write("file.jam", """
- actions .a.
- {
+t.write("file.jam", """\
+actions .a.
+{
 echo [$(<:B)] 0
 echo [$(<:B)] 1
 echo [$(<:B)] 2
- }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- .a. subtest_b : subtest ;
- DEPENDS all : subtest_a subtest_b ;
+}
+
+rule .a.
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+NOTFILE subtest ;
+.a. subtest_a : subtest ;
+.a. subtest_b : subtest ;
+DEPENDS all : subtest_a subtest_b ;
 """)
 
-t.run_build_system("-ffile.jam -d2", stdout="""...found 4 targets...
+t.run_build_system(["-ffile.jam", "-d2"], stdout="""\
+...found 4 targets...
 ...updating 2 targets...
 .a. subtest_a
 
 echo [subtest_a] 0
 echo [subtest_a] 1
 echo [subtest_a] 2
-
+
 [subtest_a] 0
 [subtest_a] 1
 [subtest_a] 2
@@ -49,7 +45,7 @@
 echo [subtest_b] 0
 echo [subtest_b] 1
 echo [subtest_b] 2
-
+
 [subtest_b] 0
 [subtest_b] 1
 [subtest_b] 2

Modified: branches/release/tools/build/v2/test/core_option_l.py
==============================================================================
--- branches/release/tools/build/v2/test/core_option_l.py (original)
+++ branches/release/tools/build/v2/test/core_option_l.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,24 +2,22 @@
 
 # Copyright 2007 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# 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 BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
 
-t.write("sleep.bat","""@setlocal
-_at_echo off
-_at_REM timeout /T %1 /NOBREAK >nul
-ping 127.0.0.1 -n 2 -w 1000 >nul
-ping 127.0.0.1 -n %1 -w 1000 >nul
-_at_endlocal
+t.write("sleep.bat", """\
+::@timeout /T %1 /NOBREAK >nul
+@ping 127.0.0.1 -n 2 -w 1000 >nul
+@ping 127.0.0.1 -n %1 -w 1000 >nul
 @exit /B 0
 """)
 
-t.write("file.jam", """
-
+t.write("file.jam", """\
 if $(NT)
 {
     SLEEP = @call sleep.bat ;
@@ -40,8 +38,7 @@
 DEPENDS all : sleeper ;
 """)
 
-t.run_build_system("-ffile.jam -d1 -l2", status=1)
-
-t.expect_output_line("2 second time limit exceeded")
+t.run_build_system(["-ffile.jam", "-d1", "-l2"], status=1)
+t.expect_output_lines("2 second time limit exceeded")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_option_n.py
==============================================================================
--- branches/release/tools/build/v2/test/core_option_n.py (original)
+++ branches/release/tools/build/v2/test/core_option_n.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,50 +2,50 @@
 
 # Copyright 2007 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
-t.write("file.jam", """
- actions .a.
- {
+t.write("file.jam", """\
+actions .a.
+{
 echo [$(<:B)] 0
 echo [$(<:B)] 1
 echo [$(<:B)] 2
- }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- .a. subtest_b : subtest ;
- FAIL_EXPECTED subtest_b ;
- DEPENDS all : subtest_a subtest_b ;
+}
+
+rule .a.
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+NOTFILE subtest ;
+.a. subtest_a : subtest ;
+.a. subtest_b : subtest ;
+FAIL_EXPECTED subtest_b ;
+DEPENDS all : subtest_a subtest_b ;
 """)
 
-t.run_build_system("-ffile.jam -n", stdout="""...found 4 targets...
+t.run_build_system(["-ffile.jam", "-n"], stdout="""\
+...found 4 targets...
 ...updating 2 targets...
 .a. subtest_a
 
 echo [subtest_a] 0
 echo [subtest_a] 1
 echo [subtest_a] 2
-
+
 .a. subtest_b
 
 echo [subtest_b] 0
 echo [subtest_b] 1
 echo [subtest_b] 2
-
+
 ...updated 2 targets...
 """)
-
 t.expect_nothing_more()
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_parallel_actions.py
==============================================================================
--- branches/release/tools/build/v2/test/core_parallel_actions.py (original)
+++ branches/release/tools/build/v2/test/core_parallel_actions.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,69 +2,68 @@
 
 # Copyright 2006 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
-t.write("sleep.bat","""@setlocal
-_at_echo off
-_at_REM timeout /T %1 /NOBREAK >nul
-ping 127.0.0.1 -n 2 -w 1000 >nul
-ping 127.0.0.1 -n %1 -w 1000 >nul
-_at_endlocal
+t.write("sleep.bat", """\
+::@timeout /T %1 /NOBREAK >nul
+@ping 127.0.0.1 -n 2 -w 1000 >nul
+@ping 127.0.0.1 -n %1 -w 1000 >nul
 @exit /B 0
 """)
 
-t.write("file.jam", """
- if $(NT)
+t.write("file.jam", """\
+if $(NT)
+{
+ actions sleeper
     {
- actions sleeper
- {
-echo [$(<:S)] 0
-_at_call sleep.bat 1
-echo [$(<:S)] 1
-_at_call sleep.bat 1
-echo [$(<:S)] 2
-_at_call sleep.bat $(<:B)
- }
+ echo [$(<:S)] 0
+ call sleep.bat 1
+ echo [$(<:S)] 1
+ call sleep.bat 1
+ echo [$(<:S)] 2
+ call sleep.bat $(<:B)
     }
- else
+}
+else
+{
+ actions sleeper
     {
- actions sleeper
- {
-echo "[$(<:S)] 0" 1>&2
-sleep 1
-echo "[$(<:S)] 1"
-sleep 1
-echo "[$(<:S)] 2" 1>&2
-sleep $(<:B)
- }
+ echo "[$(<:S)] 0"
+ sleep 1
+ echo "[$(<:S)] 1"
+ sleep 1
+ echo "[$(<:S)] 2"
+ sleep $(<:B)
     }
-
- rule sleeper
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE front ;
- sleeper 1.a : front ;
- sleeper 2.a : front ;
- sleeper 3.a : front ;
- sleeper 4.a : front ;
- NOTFILE choke ;
- DEPENDS choke : 1.a 2.a 3.a 4.a ;
- sleeper 1.b : choke ;
- sleeper 2.b : choke ;
- sleeper 3.b : choke ;
- sleeper 4.b : choke ;
- DEPENDS bottom : 1.b 2.b 3.b 4.b ;
- DEPENDS all : bottom ;
+}
+
+rule sleeper
+{
+ DEPENDS $(<) : $(>) ;
+}
+
+NOTFILE front ;
+sleeper 1.a : front ;
+sleeper 2.a : front ;
+sleeper 3.a : front ;
+sleeper 4.a : front ;
+NOTFILE choke ;
+DEPENDS choke : 1.a 2.a 3.a 4.a ;
+sleeper 1.b : choke ;
+sleeper 2.b : choke ;
+sleeper 3.b : choke ;
+sleeper 4.b : choke ;
+DEPENDS bottom : 1.b 2.b 3.b 4.b ;
+DEPENDS all : bottom ;
 """)
 
-t.run_build_system("-ffile.jam -j4", stdout="""...found 12 targets...
+t.run_build_system(["-ffile.jam", "-j4"], stdout="""\
+...found 12 targets...
 ...updating 8 targets...
 sleeper 1.a
 [.a] 0

Modified: branches/release/tools/build/v2/test/core_parallel_multifile_actions_1.py
==============================================================================
--- branches/release/tools/build/v2/test/core_parallel_multifile_actions_1.py (original)
+++ branches/release/tools/build/v2/test/core_parallel_multifile_actions_1.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,58 +2,68 @@
 
 # Copyright 2007 Rene Rivera.
 # Copyright 2011 Steven Watanabe
-# 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)
+# 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)
+
+# Added to guard against a bug causing targets to be used before they
+# themselves have finished building. This used to happen for targets built by a
+# multi-file action that got triggered by another target.
+#
+# Example:
+# When target A and target B were declared as created by a single action and
+# target A triggered running that action then, while the action was still
+# running, target B was already reporting as being built causing other targets
+# depending on target A to be built prematurely.
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
-t.write("sleep.bat","""@setlocal
-_at_echo off
-_at_REM timeout /T %1 /NOBREAK >nul
-ping 127.0.0.1 -n 2 -w 1000 >nul
-ping 127.0.0.1 -n %1 -w 1000 >nul
-_at_endlocal
+t.write("sleep.bat", """\
+::@timeout /T %1 /NOBREAK >nul
+@ping 127.0.0.1 -n 2 -w 1000 >nul
+@ping 127.0.0.1 -n %1 -w 1000 >nul
 @exit /B 0
 """)
 
-t.write("file.jam", """
+t.write("file.jam", """\
+if $(NT)
+{
+ SLEEP = @call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
 
- if $(NT)
- {
- SLEEP = @call sleep.bat ;
- }
- else
- {
- SLEEP = sleep ;
- }
-
- actions .gen. {
-echo 001
-$(SLEEP) 4
-echo 002
+actions .gen.
+{
+ echo 001
+ $(SLEEP) 4
+ echo 002
 }
- rule .use.1 { DEPENDS $(<) : $(>) ; }
- actions .use.1 {
-echo 003
+rule .use.1 { DEPENDS $(<) : $(>) ; }
+actions .use.1
+{
+ echo 003
 }
- rule .use.2 { DEPENDS $(<) : $(>) ; }
- actions .use.2 {
-$(SLEEP) 1
-echo 004
+
+rule .use.2 { DEPENDS $(<) : $(>) ; }
+actions .use.2
+{
+ $(SLEEP) 1
+ echo 004
 }
 
- .gen. g1.generated g2.generated ;
- .use.1 u1.user : g1.generated ;
- .use.2 u2.user : g2.generated ;
-
- NOTFILE root ;
- DEPENDS g1.generated g2.generated : root ;
- DEPENDS all : u1.user u2.user ;
+.gen. g1.generated g2.generated ;
+.use.1 u1.user : g1.generated ;
+.use.2 u2.user : g2.generated ;
+
+DEPENDS all : u1.user u2.user ;
 """)
 
-t.run_build_system("-ffile.jam -j2", stdout="""...found 6 targets...
+t.run_build_system(["-ffile.jam", "-j2"], stdout="""\
+...found 5 targets...
 ...updating 4 targets...
 .gen. g1.generated
 001

Modified: branches/release/tools/build/v2/test/core_parallel_multifile_actions_2.py
==============================================================================
--- branches/release/tools/build/v2/test/core_parallel_multifile_actions_2.py (original)
+++ branches/release/tools/build/v2/test/core_parallel_multifile_actions_2.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,65 +2,64 @@
 
 # Copyright 2008 Jurko Gospodnetic, Vladimir Prus
 # Copyright 2011 Steven Watanabe
-# 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)
+# 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)
 
 # Added to guard against a bug causing targets to be used before they
 # themselves have finished building. This used to happen for targets built by a
-# multi-file action that got triggered by another target, except when the target
-# triggering the action was the first one in the list of targets produced by
-# that action.
+# multi-file action that got triggered by another target, except when the
+# target triggering the action was the first one in the list of targets
+# produced by that action.
 #
 # Example:
 # When target A and target B were declared as created by a single action with
-# A being the first one listed, and target B triggered running that action then
-# while the action was still running, target A was already reporting as being
-# built causing other targets depending on target A to be built prematurely.
+# A being the first one listed, and target B triggered running that action
+# then, while the action was still running, target A was already reporting as
+# being built causing other targets depending on target A to be built
+# prematurely.
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
-t.write("sleep.bat","""@setlocal
-_at_echo off
-_at_REM timeout /T %1 /NOBREAK >nul
-ping 127.0.0.1 -n 2 -w 1000 >nul
-ping 127.0.0.1 -n %1 -w 1000 >nul
-_at_endlocal
+t.write("sleep.bat", """\
+::@timeout /T %1 /NOBREAK >nul
+@ping 127.0.0.1 -n 2 -w 1000 >nul
+@ping 127.0.0.1 -n %1 -w 1000 >nul
 @exit /B 0
 """)
 
-t.write("file.jam", """
+t.write("file.jam", """\
+if $(NT)
+{
+ SLEEP = @call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
+
+actions link
+{
+ $(SLEEP) 1
+ echo 001 - linked
+}
+
+link dll lib ;
+
+actions install
+{
+ echo 002 - installed
+}
 
- if $(NT)
- {
- SLEEP = @call sleep.bat ;
- }
- else
- {
- SLEEP = sleep ;
- }
-
- actions link
- {
- $(SLEEP) 1
- echo 001 - linked
- }
-
- link dll lib ;
-
- actions install
- {
- echo 002 - installed
- }
+install installed_dll : dll ;
+DEPENDS installed_dll : dll ;
 
- install installed_dll : dll ;
- DEPENDS installed_dll : dll ;
-
- DEPENDS all : lib installed_dll ;
+DEPENDS all : lib installed_dll ;
 """)
 
-t.run_build_system("-ffile.jam -j2", stdout="""...found 4 targets...
+t.run_build_system(["-ffile.jam", "-j2"], stdout="""\
+...found 4 targets...
 ...updating 3 targets...
 link dll
 001 - linked

Copied: branches/release/tools/build/v2/test/core_source_line_tracking.py (from r79449, /trunk/tools/build/v2/test/core_source_line_tracking.py)
==============================================================================
--- /trunk/tools/build/v2/test/core_source_line_tracking.py (original)
+++ branches/release/tools/build/v2/test/core_source_line_tracking.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 
 # Copyright 2012. Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Test Boost Jam parser's source line tracking & reporting.
 
@@ -13,8 +14,8 @@
     t = BoostBuild.Tester(pass_toolset=False)
     t.write("file.jam", '\n\n\naaa = "\n\n\n\n\n\n')
     t.run_build_system(["-ffile.jam"], status=1)
- t.expect_output_line('file.jam:4: unmatched " in string at keyword =')
- t.expect_output_line("file.jam:4: syntax error at EOF")
+ t.expect_output_lines('file.jam:4: unmatched " in string at keyword =')
+ t.expect_output_lines("file.jam:4: syntax error at EOF")
     t.cleanup()
 
 
@@ -30,8 +31,8 @@
 rule f ( param ) { }
 f ;%s""" % __trailing_newline(eof))
     t.run_build_system(["-ffile.jam"], status=1)
- t.expect_output_line("file.jam:2: in module scope")
- t.expect_output_line("file.jam:1:see definition of rule 'f' being called")
+ t.expect_output_lines("file.jam:2: in module scope")
+ t.expect_output_lines("file.jam:1:see definition of rule 'f' being called")
     t.cleanup()
 
 
@@ -39,7 +40,7 @@
     t = BoostBuild.Tester(pass_toolset=False)
     t.write("file.jam", "ECHO%s" % __trailing_newline(eof))
     t.run_build_system(["-ffile.jam"], status=1)
- t.expect_output_line("file.jam:1: syntax error at EOF")
+ t.expect_output_lines("file.jam:1: syntax error at EOF")
     t.cleanup()
 
 
@@ -49,7 +50,7 @@
 NOTFILE all ;
 ECHO [ BACKTRACE ] ;""")
     t.run_build_system(["-ffile.jam"])
- t.expect_output_line("file.jam 2 module scope")
+ t.expect_output_lines("file.jam 2 module scope")
     t.cleanup()
 
 

Modified: branches/release/tools/build/v2/test/core_typecheck.py
==============================================================================
--- branches/release/tools/build/v2/test/core_typecheck.py (original)
+++ branches/release/tools/build/v2/test/core_typecheck.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,21 +1,21 @@
 #!/usr/bin/python
 
-# Copyright 2003 Vladimir Prus
-# 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)
+# Copyright 2003 Vladimir Prus
+# 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)
 
 # This tests the typechecking facilities.
 
 import BoostBuild
 
-t = BoostBuild.Tester(pass_toolset=0)
+t = BoostBuild.Tester(["-ffile.jam"], pass_toolset=0)
 
 t.write("file.jam", """
-module .typecheck
+module .typecheck
 {
     rule [path] ( x )
     {
- if ! [ MATCH "^(::)" : $(x) ]
+ if ! [ MATCH "^(::)" : $(x) ]
         {
             ECHO "Error: $(x) is not a path" ;
             return true ;
@@ -29,13 +29,13 @@
 
 do $(ARGUMENT) ;
 
-actions dummy { }
+actions dummy { }
 dummy all ;
 """)
 
-t.run_build_system("-ffile.jam -sARGUMENT=::a/b/c")
-t.run_build_system("-ffile.jam -sARGUMENT=a/b/c", status=1,
- stdout="""Error: a/b/c is not a path
+t.run_build_system(["-sARGUMENT=::a/b/c"])
+t.run_build_system(["-sARGUMENT=a/b/c"], status=1, stdout="""\
+Error: a/b/c is not a path
 file.jam:18: in module scope
 *** argument error
 * rule do ( [path] a )

Modified: branches/release/tools/build/v2/test/core_update_now.py
==============================================================================
--- branches/release/tools/build/v2/test/core_update_now.py (original)
+++ branches/release/tools/build/v2/test/core_update_now.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,19 +1,17 @@
 #!/usr/bin/python
 
 # Copyright 2011 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 import os
 
-def basic():
- # Basic test
 
+def basic():
     t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
- t.write("file.jam", """
-
+ t.write("file.jam", """\
 actions do-print
 {
     echo updating $(<)
@@ -28,7 +26,8 @@
 DEPENDS all : target1 ;
 """)
 
- t.run_build_system("-ffile.jam", stdout="""...found 1 target...
+ t.run_build_system(["-ffile.jam"], stdout="""\
+...found 1 target...
 ...updating 1 target...
 do-print target1
 updating target1
@@ -38,13 +37,11 @@
 
     t.cleanup()
 
-def ignore_minus_n():
- # ignore-minus-n
 
+def ignore_minus_n():
     t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
- t.write("file.jam", """
-
+ t.write("file.jam", """\
 actions do-print
 {
     echo updating $(<)
@@ -59,7 +56,8 @@
 DEPENDS all : target1 ;
 """)
 
- t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+ t.run_build_system(["-ffile.jam", "-n"], stdout="""\
+...found 1 target...
 ...updating 1 target...
 do-print target1
 
@@ -72,12 +70,11 @@
 
     t.cleanup()
 
-def failed_target():
 
+def failed_target():
     t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
- t.write("file.jam", """
-
+ t.write("file.jam", """\
 actions fail
 {
     exit 1
@@ -101,7 +98,8 @@
 DEPENDS all : target1 target2 ;
 """)
 
- t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+ t.run_build_system(["-ffile.jam", "-n"], stdout="""\
+...found 1 target...
 ...updating 1 target...
 fail target1
 
@@ -120,11 +118,11 @@
 
     t.cleanup()
 
+
 def missing_target():
     t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
- t.write("file.jam", """
-
+ t.write("file.jam", """\
 actions do-print
 {
     echo updating $(<)
@@ -139,7 +137,8 @@
 DEPENDS all : target1 target2 ;
 """)
 
- t.run_build_system("-ffile.jam -n", status=1, stdout="""don't know how to make target1
+ t.run_build_system(["-ffile.jam", "-n"], status=1, stdout="""\
+don't know how to make target1
 ...found 1 target...
 ...can't find 1 target...
 ...found 2 targets...
@@ -148,15 +147,17 @@
 
     t.cleanup()
 
-# Make sure that if we call UPDATE_NOW with ignore-minus-n,
-# the target gets updated exactly once regardless of previous
-# calls to UPDATE_NOW with -n in effect.
 
 def build_once():
- t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+ """
+ Make sure that if we call UPDATE_NOW with ignore-minus-n, the target gets
+ updated exactly once regardless of previous calls to UPDATE_NOW with -n in
+ effect.
 
- t.write("file.jam", """
+ """
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
 
+ t.write("file.jam", """\
 actions do-print
 {
     echo updating $(<)
@@ -173,7 +174,8 @@
 DEPENDS all : target1 ;
 """)
 
- t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+ t.run_build_system(["-ffile.jam", "-n"], stdout="""\
+...found 1 target...
 ...updating 1 target...
 do-print target1
 
@@ -191,8 +193,185 @@
 
     t.cleanup()
 
+
+def return_status():
+ """
+ Make sure that UPDATE_NOW returns a failure status if
+ the target failed in a previous call to UPDATE_NOW
+ """
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """\
+actions fail
+{
+ exit 1
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+fail target1 ;
+
+ECHO update1: [ UPDATE_NOW target1 ] ;
+ECHO update2: [ UPDATE_NOW target1 ] ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system(["-ffile.jam"], status=1, stdout="""\
+...found 1 target...
+...updating 1 target...
+fail target1
+
+ exit 1
+
+...failed fail target1...
+...failed updating 1 target...
+update1:
+update2:
+...found 1 target...
+""")
+
+ t.cleanup()
+
+
+def save_restore():
+ """Tests that ignore-minus-n and ignore-minus-q are
+ local to the call to UPDATE_NOW"""
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("actions.jam", """\
+rule fail
+{
+ NOTFILE $(<) ;
+ ALWAYS $(<) ;
+}
+actions fail
+{
+ exit 1
+}
+
+rule pass
+{
+ NOTFILE $(<) ;
+ ALWAYS $(<) ;
+}
+actions pass
+{
+ echo updating $(<)
+}
+""")
+ t.write("file.jam", """
+include actions.jam ;
+fail target1 ;
+fail target2 ;
+UPDATE_NOW target1 target2 : : $(IGNORE_MINUS_N) : $(IGNORE_MINUS_Q) ;
+fail target3 ;
+fail target4 ;
+UPDATE_NOW target3 target4 ;
+UPDATE ;
+""")
+ t.run_build_system(['-n', '-sIGNORE_MINUS_N=1', '-ffile.jam'],
+ stdout='''...found 2 targets...
+...updating 2 targets...
+fail target1
+
+ exit 1
+
+...failed fail target1...
+fail target2
+
+ exit 1
+
+...failed fail target2...
+...failed updating 2 targets...
+...found 2 targets...
+...updating 2 targets...
+fail target3
+
+ exit 1
+
+fail target4
+
+ exit 1
+
+...updated 2 targets...
+''')
+
+ t.run_build_system(['-q', '-sIGNORE_MINUS_N=1', '-ffile.jam'],
+ status=1, stdout='''...found 2 targets...
+...updating 2 targets...
+fail target1
+
+ exit 1
+
+...failed fail target1...
+...failed updating 1 target...
+...found 2 targets...
+...updating 2 targets...
+fail target3
+
+ exit 1
+
+...failed fail target3...
+...failed updating 1 target...
+''')
+
+ t.run_build_system(['-n', '-sIGNORE_MINUS_Q=1', '-ffile.jam'],
+ stdout='''...found 2 targets...
+...updating 2 targets...
+fail target1
+
+ exit 1
+
+fail target2
+
+ exit 1
+
+...updated 2 targets...
+...found 2 targets...
+...updating 2 targets...
+fail target3
+
+ exit 1
+
+fail target4
+
+ exit 1
+
+...updated 2 targets...
+''')
+
+ t.run_build_system(['-q', '-sIGNORE_MINUS_Q=1', '-ffile.jam'],
+ status=1, stdout='''...found 2 targets...
+...updating 2 targets...
+fail target1
+
+ exit 1
+
+...failed fail target1...
+fail target2
+
+ exit 1
+
+...failed fail target2...
+...failed updating 2 targets...
+...found 2 targets...
+...updating 2 targets...
+fail target3
+
+ exit 1
+
+...failed fail target3...
+...failed updating 1 target...
+''')
+
+ t.cleanup()
+
+
 basic()
 ignore_minus_n()
 failed_target()
 missing_target()
 build_once()
+return_status()
+save_restore()

Copied: branches/release/tools/build/v2/test/core_variables_in_actions.py (from r78670, /trunk/tools/build/v2/test/core_variables_in_actions.py)
==============================================================================
--- /trunk/tools/build/v2/test/core_variables_in_actions.py (original)
+++ branches/release/tools/build/v2/test/core_variables_in_actions.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,22 +2,23 @@
 
 # Copyright 2012. Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
-# Tests that variables in actions get expanded but double quote characters get
-# treated as regular characters and not string literal delimiters when
+# Tests that variables in actions get expanded but double quote characters
+# get treated as regular characters and not string literal delimiters when
 # determining string tokens concatenated to the variable being expanded.
 #
 # We also take care to make this test work correctly when run using both
 # Windows and Unix echo command variant. That is why we add the extra single
 # quotes around the text being echoed - they will make the double quotes be
-# displayed as regular characters in both cases but will be displayed themselves
-# only when using the Windows cmd shell's echo command.
+# displayed as regular characters in both cases but will be displayed
+# themselves only when using the Windows cmd shell's echo command.
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
-t.write("file.jam", """
+t.write("file.jam", """\
 rule dummy ( i )
 {
     local a = 1 2 3 ;
@@ -32,7 +33,7 @@
 
 dummy all ;
 """)
-t.run_build_system("-ffile.jam -d1")
-t.expect_output_line("From rule: 1 seconds 2 seconds 3 seconds")
-t.expect_output_line('*From action: 1" 2" 3" seconds"*')
+t.run_build_system(["-ffile.jam", "-d1"])
+t.expect_output_lines("From rule: 1 seconds 2 seconds 3 seconds")
+t.expect_output_lines('*From action: 1" 2" 3" seconds"*')
 t.cleanup()

Modified: branches/release/tools/build/v2/test/core_varnames.py
==============================================================================
--- branches/release/tools/build/v2/test/core_varnames.py (original)
+++ branches/release/tools/build/v2/test/core_varnames.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,7 +10,7 @@
 
 t = BoostBuild.Tester(pass_toolset=0)
 
-t.write("file.jam", """
+t.write("file.jam", """\
 module foo
 {
     rule bar { }
@@ -33,6 +33,6 @@
 NOTFILE xx ;
 """)
 
-t.run_build_system("-ffile.jam", status=0)
+t.run_build_system(["-ffile.jam"], status=0)
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/default_build.py
==============================================================================
--- branches/release/tools/build/v2/test/default_build.py (original)
+++ branches/release/tools/build/v2/test/default_build.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,9 +9,9 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", "import gcc ;")
+t.write("jamroot.jam", "")
 t.write("jamfile.jam", "exe a : a.cpp : : debug release ;")
 t.write("a.cpp", "int main() {}\n")
 
@@ -21,53 +21,43 @@
 
 # Check that explictly-specified build variant supresses default-build.
 t.rm("bin")
-t.run_build_system("release")
+t.run_build_system(["release"])
 t.expect_addition(BoostBuild.List("bin/$toolset/release/") * "a.exe a.obj")
 t.expect_nothing_more()
 
 # Now check that we can specify explicit build request and default-build will be
 # combined with it.
-t.run_build_system("optimization=space")
+t.run_build_system(["optimization=space"])
 t.expect_addition("bin/$toolset/debug/optimization-space/a.exe")
 t.expect_addition("bin/$toolset/release/optimization-space/a.exe")
 
 # Test that default-build must be identical in all alternatives. Error case.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp : : debug ;
 exe a : b.cpp : : ;
 """)
-expected="""error: default build must be identical in all alternatives
-main target is ./a
-with
-differing from previous default build <variant>debug
-
-"""
-t.run_build_system("-n --no-error-backtrace", status=1)
+t.run_build_system(["-n", "--no-error-backtrace"], status=1)
 t.fail_test(t.stdout().find("default build must be identical in all alternatives") == -1)
 
 # Test that default-build must be identical in all alternatives. No Error case,
 # empty default build.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp : <variant>debug ;
 exe a : b.cpp : <variant>release ;
 """)
-t.run_build_system("-n --no-error-backtrace", status=0)
-
+t.run_build_system(["-n", "--no-error-backtrace"], status=0)
 
 # Now try a harder example: default build which contains <define> should cause
 # <define> to be present when "b" is compiled. This happens only if
 # "build-project b" is placed first.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 project : default-build <define>FOO ;
 build-project a ;
 build-project b ;
 """)
 
-t.write("a/jamfile.jam", """
-exe a : a.cpp ../b//b ;
-""")
-
-t.write("a/a.cpp", """
+t.write("a/jamfile.jam", "exe a : a.cpp ../b//b ;")
+t.write("a/a.cpp", """\
 #ifdef _WIN32
 __declspec(dllimport)
 #endif
@@ -75,11 +65,8 @@
 int main() { foo(); }
 """)
 
-t.write("b/jamfile.jam", """
-lib b : b.cpp ;
-""")
-
-t.write("b/b.cpp", """
+t.write("b/jamfile.jam", "lib b : b.cpp ;")
+t.write("b/b.cpp", """\
 #ifdef FOO
 #ifdef _WIN32
 __declspec(dllexport)

Modified: branches/release/tools/build/v2/test/default_features.py
==============================================================================
--- branches/release/tools/build/v2/test/default_features.py (original)
+++ branches/release/tools/build/v2/test/default_features.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,7 +9,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Declare *non-propagated* feature foo.
 t.write("jamroot.jam", """

Modified: branches/release/tools/build/v2/test/default_toolset.py
==============================================================================
--- branches/release/tools/build/v2/test/default_toolset.py (original)
+++ branches/release/tools/build/v2/test/default_toolset.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,13 +2,14 @@
 
 # Copyright 2008 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Test that the expected default toolset is used when no toolset is explicitly
 # specified on the command line or used from code via the using rule. Test that
 # the default toolset is correctly used just like any other explicitly used
-# toolset (e.g. toolset prerequisites, properties conditioned on toolset related
-# features, etc.).
+# toolset (e.g. toolset prerequisites, properties conditioned on toolset
+# related features, etc.).
 #
 # Note that we need to ignore regular site/user/test configuration files to
 # avoid them marking any toolsets not under our control as used.
@@ -21,12 +22,12 @@
     'warning: Configuring default toolset "%s".'
 
 
-################################################################################
+###############################################################################
 #
 # test_conditions_on_default_toolset()
 # ------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_conditions_on_default_toolset():
     """Test that toolset and toolset subfeature conditioned properties get
@@ -93,22 +94,23 @@
     'toolset_version_unused': toolset_version_unused})
 
     t.run_build_system()
- t.expect_output_line(configuring_default_toolset_message % toolset_name)
- t.expect_output_line(message_loaded)
- t.expect_output_line(message_initialized)
- t.expect_output_line("descriptions: /stand-alone/ /toolset/ /toolset-version/")
- t.expect_output_line("toolset: /%s/" % toolset_name)
- t.expect_output_line("toolset-version: /%s/" % toolset_version)
+ t.expect_output_lines(configuring_default_toolset_message % toolset_name)
+ t.expect_output_lines(message_loaded)
+ t.expect_output_lines(message_initialized)
+ t.expect_output_lines("descriptions: /stand-alone/ /toolset/ "
+ "/toolset-version/")
+ t.expect_output_lines("toolset: /%s/" % toolset_name)
+ t.expect_output_lines("toolset-version: /%s/" % toolset_version)
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_default_toolset_on_os()
 # ----------------------------
 #
-################################################################################
+###############################################################################
 
 def test_default_toolset_on_os( os, expected_toolset ):
     """Test that the given toolset is used as the default toolset on the given
@@ -127,17 +129,18 @@
     # load missing toolsets might cause random failures with which we are not
     # concerned in this test.
     t.run_build_system(stderr=None)
- t.expect_output_line(configuring_default_toolset_message % expected_toolset)
+ t.expect_output_lines(configuring_default_toolset_message %
+ expected_toolset)
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_default_toolset_requirements()
 # -----------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_default_toolset_requirements():
     """Test that default toolset's requirements get applied correctly.
@@ -189,19 +192,20 @@
 """ % {'toolset_name': toolset_name})
 
     t.run_build_system()
- t.expect_output_line(configuring_default_toolset_message % toolset_name)
- t.expect_output_line("descriptions: /conditioned-requirement/ /target-requirement/ /toolset-requirement/")
- t.expect_output_line("toolset: /%s/" % toolset_name)
+ t.expect_output_lines(configuring_default_toolset_message % toolset_name)
+ t.expect_output_lines("descriptions: /conditioned-requirement/ "
+ "/target-requirement/ /toolset-requirement/")
+ t.expect_output_lines("toolset: /%s/" % toolset_name)
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
 test_default_toolset_on_os("NT" , "msvc")
 test_default_toolset_on_os("LINUX" , "gcc" )

Modified: branches/release/tools/build/v2/test/dependency_property.py
==============================================================================
--- branches/release/tools/build/v2/test/dependency_property.py (original)
+++ branches/release/tools/build/v2/test/dependency_property.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,8 +6,8 @@
 
 # Regression test: virtual targets with different dependency properties were
 # considered different by 'virtual-target.register', but the code which
-# determined target paths ignored dependency properties --- so both targets used
-# to be placed to the same location.
+# determined the actual target paths ignored dependency properties so both
+# targets ended up being in the same location.
 
 import BoostBuild
 import string
@@ -15,7 +15,7 @@
 
 t = BoostBuild.Tester()
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 lib foo : foo.cpp ;
 exe hello : hello.cpp ;
 exe hello2 : hello.cpp : <library>foo ;
@@ -23,14 +23,14 @@
 
 t.write("hello.cpp", "int main() {}\n")
 
-t.write("foo.cpp", """
+t.write("foo.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
 void foo() {}
 """)
 
-t.run_build_system("--no-error-backtrace", status=1)
+t.run_build_system(["--no-error-backtrace"], status=1)
 t.fail_test(string.find(t.stdout(), "Duplicate name of actual target") == -1)
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/dependency_test.py
==============================================================================
--- branches/release/tools/build/v2/test/dependency_test.py (original)
+++ branches/release/tools/build/v2/test/dependency_test.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -3,102 +3,237 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2002, 2003, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
-t = BoostBuild.Tester()
 
-t.set_tree("dependency-test")
+def test_basic():
+ t = BoostBuild.Tester(["-d3", "-d+12"], pass_d0=False, use_test_config=False)
 
-t.run_build_system()
+ t.write("a.cpp", """
+#include <a.h>
+# include "a.h"
+#include <x.h>
+int main() {}
+""")
+ t.write("a.h", "\n")
+ t.write("a_c.c", """\
+#include <a.h>
+# include "a.h"
+#include <x.h>
+""")
+ t.write("b.cpp", """\
+#include "a.h"
+int main() {}
+""")
+ t.write("b.h", "\n")
+ t.write("c.cpp", """\
+#include "x.h"
+int main() {}
+""")
+ t.write("e.cpp", """\
+#include "x.h"
+int main() {}
+""")
+ t.write("x.foo", "")
+ t.write("y.foo", "")
 
-# Check that main target 'c' was able to find 'x.h' from 'a's dependency graph.
-t.expect_addition("bin/$toolset/debug/c.exe")
+ t.write("src1/a.h", '#include "b.h"\n')
+ t.write("src1/b.h", '#include "c.h"\n')
+ t.write("src1/c.h", "\n")
+ t.write("src1/z.h", """\
+extern int dummy_variable_suppressing_empty_file_warning_on_hp_cxx_compiler;
+""")
 
-# Check handling of first level includes.
-
-# Both 'a' and 'b' include "a.h" and should be updated.
-t.touch("a.h")
-t.run_build_system()
-
-t.expect_touch("bin/$toolset/debug/a.exe")
-t.expect_touch("bin/$toolset/debug/a.obj")
-t.expect_touch("bin/$toolset/debug/a_c.obj")
-t.expect_touch("bin/$toolset/debug/b.exe")
-t.expect_touch("bin/$toolset/debug/b.obj")
-# Now, <dependency> does not add a dependency. It sound weird, but is
-# intentional. Need to rename <dependency> eventually.
-#t.expect_touch("bin/$toolset/debug/main-target-c/c.exe")
-t.ignore("*.tds")
-t.expect_nothing_more()
-
-# Only 'a' include <a.h> and should be updated.
-t.touch("src1/a.h")
-t.run_build_system()
-
-t.expect_touch("bin/$toolset/debug/a.exe")
-t.expect_touch("bin/$toolset/debug/a.obj")
-t.expect_touch("bin/$toolset/debug/a_c.obj")
-t.ignore("*.tds")
-t.expect_nothing_more()
-
-# "src/a.h" includes "b.h" (in the same dir).
-t.touch("src1/b.h")
-t.run_build_system()
-t.expect_touch("bin/$toolset/debug/a.exe")
-t.expect_touch("bin/$toolset/debug/a.obj")
-t.expect_touch("bin/$toolset/debug/a_c.obj")
-t.ignore("*.tds")
-t.expect_nothing_more()
-
-# Included by "src/b.h". We had a bug: file included via "", like "b.h" is in
-# this case was not scanned at all.
-t.touch("src1/c.h")
-t.run_build_system()
-t.expect_touch("bin/$toolset/debug/a.exe")
-
-t.touch("b.h")
-t.run_build_system()
-t.expect_nothing_more()
+ t.write("src2/b.h", "\n")
 
-# Test dependency on a generated header.
+ t.write("jamroot.jam", """\
+import foo ;
+import types/cpp ;
+import types/exe ;
+
+project test : requirements <include>src1 ;
+
+exe a : x.foo a.cpp a_c.c ;
+exe b : b.cpp ;
+
+# Because of <define>FOO, c.cpp will be compiled to a different directory than
+# everything for main target "a". Therefore, without <implicit-dependency>, C
+# preprocessor processing that module will not find "x.h", which is part of
+# "a"'s dependency graph.
+#
+# --------------------------
+# More detailed explanation:
+# --------------------------
+# c.cpp includes x.h which does not exist on the current include path so Boost
+# Jam will try to match it to existing Jam targets to cover cases as this one
+# where the file is generated by the same build.
 #
-# TODO: we have also to check that generated header is found correctly if it is
-# different for different subvariants. Lacking any toolset support, this check
-# will be implemented later.
-t.touch("x.foo")
-t.run_build_system()
-t.expect_touch("bin/$toolset/debug/a.obj")
-t.expect_touch("bin/$toolset/debug/a_c.obj")
-
-# Check that generated headers are scanned for dependencies as well.
-t.touch("src1/z.h")
-t.run_build_system()
-t.expect_touch("bin/$toolset/debug/a.obj")
-t.expect_touch("bin/$toolset/debug/a_c.obj")
-
-# Regression test: on Windows, <includes> with absolute paths were not
-# considered when scanning dependencies.
-t.rm(".")
+# However, as x.h is not part of "c" metatarget's dependency graph, Boost
+# Build will not actualize its target by default, i.e. create its Jam target.
+#
+# To get the Jam target created in time, we use the <implicit-dependency>
+# feature. This tells Boost Build that it needs to actualize the dependency
+# graph for metatarget "a", even though that metatarget has not been directly
+# mentioned and is not a dependency for any of the metatargets mentioned in the
+# current build request.
+#
+# Note that Boost Build does not automatically add a dependency between the
+# Jam targets in question so, if Boost Jam does not add a dependency on a target
+# from that other dependency graph (x.h in our case), i.e. if c.cpp does not
+# actually include x.h, us actualizing it will have no effect in the end as
+# Boost Jam will not have a reason to actually build those targets in spite of
+# knowing about them.
+exe c : c.cpp : <define>FOO <implicit-dependency>a ;
+""")
 
-t.write("jamroot.jam", """
+ t.write("foo.jam", """\
+import generators ;
+import modules ;
+import os ;
+import print ;
+import type ;
+import types/cpp ;
+
+type.register FOO : foo ;
+
+generators.register-standard foo.foo : FOO : CPP H ;
+
+nl = "
+" ;
+
+rule foo ( targets * : sources * : properties * )
+{
+ # On NT, you need an exported symbol in order to have an import library
+ # generated. We will not really use the symbol defined here, just force the
+ # import library creation.
+ if ( [ os.name ] = NT || [ modules.peek : OS ] in CYGWIN ) &&
+ <main-target-type>LIB in $(properties)
+ {
+ .decl = "void __declspec(dllexport) foo() {}" ;
+ }
+ print.output $(<[1]) ;
+ print.text $(.decl:E="//")$(nl) ;
+ print.output $(<[2]) ;
+ print.text "#include <z.h>"$(nl) ;
+}
+""")
+
+ t.write("foo.py",
+r"""import bjam
+import b2.build.type as type
+import b2.build.generators as generators
+
+from b2.manager import get_manager
+
+type.register("FOO", ["foo"])
+generators.register_standard("foo.foo", ["FOO"], ["CPP", "H"])
+
+def prepare_foo(targets, sources, properties):
+ if properties.get('os') in ['windows', 'cygwin']:
+ bjam.call('set-target-variable', targets, "DECL",
+ "void __declspec(dllexport) foo() {}")
+
+get_manager().engine().register_action("foo.foo",
+ "echo -e $(DECL:E=//)\\n > $(<[1])\n"
+ "echo -e "#include <z.h>\\n" > $(<[2])\n", function=prepare_foo)
+""")
+
+ # Check that main target 'c' was able to find 'x.h' from 'a's dependency
+ # graph.
+ t.run_build_system()
+ t.expect_addition("bin/$toolset/debug/c.exe")
+
+ # Check handling of first level includes.
+
+ # Both 'a' and 'b' include "a.h" and should be updated.
+ t.touch("a.h")
+ t.run_build_system()
+
+ t.expect_touch("bin/$toolset/debug/a.exe")
+ t.expect_touch("bin/$toolset/debug/a.obj")
+ t.expect_touch("bin/$toolset/debug/a_c.obj")
+ t.expect_touch("bin/$toolset/debug/b.exe")
+ t.expect_touch("bin/$toolset/debug/b.obj")
+ t.expect_nothing_more()
+
+ # Only source files using include <a.h> should be compiled.
+ t.touch("src1/a.h")
+ t.run_build_system()
+
+ t.expect_touch("bin/$toolset/debug/a.exe")
+ t.expect_touch("bin/$toolset/debug/a.obj")
+ t.expect_touch("bin/$toolset/debug/a_c.obj")
+ t.expect_nothing_more()
+
+ # "src/a.h" includes "b.h" (in the same dir).
+ t.touch("src1/b.h")
+ t.run_build_system()
+ t.expect_touch("bin/$toolset/debug/a.exe")
+ t.expect_touch("bin/$toolset/debug/a.obj")
+ t.expect_touch("bin/$toolset/debug/a_c.obj")
+ t.expect_nothing_more()
+
+ # Included by "src/b.h". We had a bug: file included using double quotes
+ # (e.g. "b.h") was not scanned at all in this case.
+ t.touch("src1/c.h")
+ t.run_build_system()
+ t.expect_touch("bin/$toolset/debug/a.exe")
+
+ t.touch("b.h")
+ t.run_build_system()
+ t.expect_nothing_more()
+
+ # Test dependency on a generated header.
+ #
+ # TODO: we have also to check that generated header is found correctly if
+ # it is different for different subvariants. Lacking any toolset support,
+ # this check will be implemented later.
+ t.touch("x.foo")
+ t.run_build_system()
+ t.expect_touch("bin/$toolset/debug/a.obj")
+ t.expect_touch("bin/$toolset/debug/a_c.obj")
+
+ # Check that generated headers are scanned for dependencies as well.
+ t.touch("src1/z.h")
+ t.run_build_system()
+ t.expect_touch("bin/$toolset/debug/a.obj")
+ t.expect_touch("bin/$toolset/debug/a_c.obj")
+
+ t.cleanup()
+
+
+def test_scanned_includes_with_absolute_paths():
+ """
+ Regression test: on Windows, <includes> with absolute paths were not
+ considered when scanning dependencies.
+
+ """
+ t = BoostBuild.Tester(["-d3", "-d+12"], pass_d0=False)
+
+ t.write("jamroot.jam", """\
 path-constant TOP : . ;
 exe app : main.cpp : <include>$(TOP)/include ;
 """);
 
-t.write("main.cpp", """
+ t.write("main.cpp", """\
 #include <dir/header.h>
 int main() {}
 """)
 
-t.write("include/dir/header.h", "")
+ t.write("include/dir/header.h", "\n")
+
+ t.run_build_system()
+ t.expect_addition("bin/$toolset/debug/main.obj")
+
+ t.touch("include/dir/header.h")
+ t.run_build_system()
+ t.expect_touch("bin/$toolset/debug/main.obj")
 
-t.run_build_system()
-t.expect_addition("bin/$toolset/debug/main.obj")
+ t.cleanup()
 
-t.touch("include/dir/header.h")
-t.run_build_system()
-t.expect_touch("bin/$toolset/debug/main.obj")
 
-t.cleanup()
+test_basic()
+test_scanned_includes_with_absolute_paths()

Modified: branches/release/tools/build/v2/test/direct_request_test.py
==============================================================================
--- branches/release/tools/build/v2/test/direct_request_test.py (original)
+++ branches/release/tools/build/v2/test/direct_request_test.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,72 +2,67 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # First check some startup.
 
 t.write("jamroot.jam", "")
-
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp b ;
 lib b : b.cpp ;
 """)
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 void
 # ifdef _WIN32
 __declspec(dllimport)
-# endif
+# endif
 foo();
-
-int main()
-{
- foo();
-}
+int main() { foo(); }
 """)
 
-t.write("b.cpp", """
+t.write("b.cpp", """\
 #ifdef MACROS
 void
 # ifdef _WIN32
 __declspec(dllexport)
-# endif
+# endif
 foo() {}
 #endif
 
 # ifdef _WIN32
 int __declspec(dllexport) force_implib_creation;
-# endif
+# endif
 """)
 
-t.run_build_system(extra_args="define=MACROS")
-t.expect_addition("bin/$toolset/debug/"
+t.run_build_system(["define=MACROS"])
+t.expect_addition("bin/$toolset/debug/"
                   * (BoostBuild.List("a.obj b.obj b.dll a.exe")))
 
 
 # When building a debug version, the 'define' still applies.
 t.rm("bin")
-t.run_build_system(extra_args="debug define=MACROS")
-t.expect_addition("bin/$toolset/debug/"
+t.run_build_system(["debug", "define=MACROS"])
+t.expect_addition("bin/$toolset/debug/"
                   * (BoostBuild.List("a.obj b.obj b.dll a.exe")))
 
 
-# When building release version, the 'define' still applies.
-t.write("jamfile.jam", """
+# When building a release version, the 'define' still applies.
+t.write("jamfile.jam", """\
 exe a : a.cpp b : <variant>debug ;
 lib b : b.cpp ;
 """)
 t.rm("bin")
-t.run_build_system(extra_args="release define=MACROS")
+t.run_build_system(["release", "define=MACROS"])
 
 
-# Regression test: direct build request was not working when there was more than
-# one level of 'build-project'.
+# Regression test: direct build request was not working when there was more
+# than one level of 'build-project'.
 t.rm(".")
-t.write('jamroot.jam', '')
-t.write('jamfile.jam', 'build-project a ;')
-t.write('a/jamfile.jam', 'build-project b ;')
-t.write('a/b/jamfile.jam', '')
-t.run_build_system("release")
+t.write("jamroot.jam", "")
+t.write("jamfile.jam", "build-project a ;")
+t.write("a/jamfile.jam", "build-project b ;")
+t.write("a/b/jamfile.jam", "")
+t.run_build_system(["release"])
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/disambiguation.py
==============================================================================
--- branches/release/tools/build/v2/test/disambiguation.py (original)
+++ branches/release/tools/build/v2/test/disambiguation.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,7 +11,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 exe hello.exe : hello.obj ;

Modified: branches/release/tools/build/v2/test/dll_path.py
==============================================================================
--- branches/release/tools/build/v2/test/dll_path.py (original)
+++ branches/release/tools/build/v2/test/dll_path.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,44 +1,38 @@
 #!/usr/bin/python
 
-# Copyright (C) Vladimir Prus 2003. Permission to copy, use, modify, sell and
-# distribute this software is granted provided this copyright notice appears in
-# all copies. This software is provided "as is" without express or implied
-# warranty, and with no claim as to its suitability for any purpose.
+# Copyright (C) 2003. Vladimir Prus
+# 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)
 
 # Test that the <dll-path> property is correctly set when using
 # <hardcode-dll-paths>true.
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # The point of this test is to have exe "main" which uses library "b", which
-# uses library "a". When "main" is built with <hardcode-dll-paths>true, paths to
-# both libraries should be present as values of <dll-path> feature. We create a
-# special target type which reports <dll-path> values on its sources and compare
-# the list of found values with out expectations.
+# uses library "a". When "main" is built with <hardcode-dll-paths>true, paths
+# to both libraries should be present as values of <dll-path> feature. We
+# create a special target type which reports <dll-path> values on its sources
+# and compare the list of found values with out expectations.
 
-t.write("jamfile.jam", """
+t.write("jamroot.jam", "using dll_paths ;")
+t.write("jamfile.jam", """\
 exe main : main.cpp b//b ;
 explicit main ;
 path-list mp : main ;
 """)
 
-t.write("main.cpp", """
-int main() {}
-""")
-
-t.write("jamroot.jam", """
-using dll_paths ;
-""")
-
-t.write("dll_paths.jam", """
-import type ;
-import generators ;
+t.write("main.cpp", "int main() {}\n")
+t.write("dll_paths.jam", """\
+import "class" : new ;
 import feature ;
-import sequence ;
+import generators ;
 import print ;
-import "class" : new ;
+import sequence ;
+import type ;
 
 rule init ( )
 {
@@ -66,7 +60,6 @@
             return [ generator.generated-targets $(sources) :
                 [ $(property-set).add-raw $(dll-paths:G=<dll-path>) ] :
                 $(project) $(name) ] ;
-
         }
     }
     generators.register [ new dll-paths-list-generator ] ;
@@ -81,7 +74,7 @@
 }
 """)
 
-t.write("dll_paths.py", """
+t.write("dll_paths.py", """\
 import bjam
 
 import b2.build.type as type
@@ -95,10 +88,10 @@
     class DllPathsListGenerator(generators.Generator):
 
         def __init__(self):
- generators.Generator.__init__(self, "dll_paths.list", False, ["EXE"], ["PATH_LIST"])
+ generators.Generator.__init__(self, "dll_paths.list", False,
+ ["EXE"], ["PATH_LIST"])
 
         def generated_targets(self, sources, ps, project, name):
-
             dll_paths = []
             for s in sources:
                 a = s.action()
@@ -106,9 +99,9 @@
                     p = a.properties()
                     dll_paths += p.get('dll-path')
             dll_paths.sort()
- return generators.Generator.generated_targets(self,
- sources, ps.add_raw(["<dll-path>" + p for p in dll_paths]),
- project, name)
+ return generators.Generator.generated_targets(self, sources,
+ ps.add_raw(["<dll-path>" + p for p in dll_paths]), project,
+ name)
 
     generators.register(DllPathsListGenerator())
 
@@ -117,11 +110,13 @@
 \"\"\"
 def function(target, sources, ps):
     bjam.call('set-target-variable', target, "PATHS", ps.get('dll-path'))
-
-get_manager().engine().register_action("dll_paths.list", command, function=function)
+
+get_manager().engine().register_action("dll_paths.list", command,
+ function=function)
 """)
 
-t.write("a/a.cpp", """
+t.write("a/jamfile.jam", "lib a : a.cpp ;")
+t.write("a/a.cpp", """\
 void
 #if defined(_WIN32)
 __declspec(dllexport)
@@ -129,11 +124,8 @@
 foo() {}
 """)
 
-t.write("a/jamfile.jam", """
-lib a : a.cpp ;
-""")
-
-t.write("b/b.cpp", """
+t.write("b/jamfile.jam", "lib b : b.cpp ../a//a ;")
+t.write("b/b.cpp", """\
 void
 #if defined(_WIN32)
 __declspec(dllexport)
@@ -141,18 +133,14 @@
 bar() {}
 """)
 
-t.write("b/jamfile.jam", """
-lib b : b.cpp ../a//a ;
-""")
-
-t.run_build_system("hardcode-dll-paths=true")
+t.run_build_system(["hardcode-dll-paths=true"])
 
 t.expect_addition("bin/$toolset/debug/mp.pathlist")
 
-es1 = t.adjust_names(["a/bin/$toolset/debug"])[0]
-es2 = t.adjust_names(["b/bin/$toolset/debug"])[0]
+es1 = t.adjust_names("a/bin/$toolset/debug")[0]
+es2 = t.adjust_names("b/bin/$toolset/debug")[0]
 
-t.expect_content_line("bin/$toolset/debug/mp.pathlist", "*" + es1);
-t.expect_content_line("bin/$toolset/debug/mp.pathlist", "*" + es2);
+t.expect_content_lines("bin/$toolset/debug/mp.pathlist", "*" + es1);
+t.expect_content_lines("bin/$toolset/debug/mp.pathlist", "*" + es2);
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/double_loading.py
==============================================================================
--- branches/release/tools/build/v2/test/double_loading.py (original)
+++ branches/release/tools/build/v2/test/double_loading.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,26 +2,27 @@
 
 # Copyright 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester()
 
 # Regression test for double loading of the same Jamfile.
-t.write("jamroot.jam", "" )
+t.write("jamroot.jam", "")
 t.write("jamfile.jam", "build-project subdir ;")
 t.write("subdir/jamfile.jam", 'ECHO "Loaded subdir" ;')
 
 t.run_build_system(subdir="subdir")
-t.expect_output_line("Loaded subdir")
+t.expect_output_lines("Loaded subdir")
 
 
 # Regression test for a more contrived case. The top-level Jamfile refers to
-# subdir via use-project, while subdir's Jamfile is being loaded. The motivation
-# why use-project referring to subprojects is useful can be found at
-# http://article.gmane.org/gmane.comp.lib.boost.build/3906/
-t.write("jamroot.jam", "" )
+# subdir via use-project, while subdir's Jamfile is being loaded. The
+# motivation why use-project referring to subprojects is useful can be found
+# at: http://article.gmane.org/gmane.comp.lib.boost.build/3906
+t.write("jamroot.jam", "")
 t.write("jamfile.jam", "use-project /subdir : subdir ;")
 t.write("subdir/jamfile.jam", "project subdir ;")
 

Modified: branches/release/tools/build/v2/test/example_libraries.py
==============================================================================
--- branches/release/tools/build/v2/test/example_libraries.py (original)
+++ branches/release/tools/build/v2/test/example_libraries.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,7 +9,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.set_tree("../example/libraries")
 

Modified: branches/release/tools/build/v2/test/example_make.py
==============================================================================
--- branches/release/tools/build/v2/test/example_make.py (original)
+++ branches/release/tools/build/v2/test/example_make.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,13 +8,10 @@
 # Test the 'make' example.
 
 import BoostBuild
+import sys
 
-t = BoostBuild.Tester()
-
+t = BoostBuild.Tester(['example.python.interpreter=%s' % sys.executable])
 t.set_tree("../example/make")
-
 t.run_build_system()
-
 t.expect_addition(["bin/$toolset/debug/main.cpp"])
-
 t.cleanup()

Modified: branches/release/tools/build/v2/test/expansion.py
==============================================================================
--- branches/release/tools/build/v2/test/expansion.py (original)
+++ branches/release/tools/build/v2/test/expansion.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,7 +7,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("a.cpp", """
 #ifdef CF_IS_OFF

Modified: branches/release/tools/build/v2/test/explicit.py
==============================================================================
--- branches/release/tools/build/v2/test/explicit.py (original)
+++ branches/release/tools/build/v2/test/explicit.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,17 +6,15 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 exe hello : hello.cpp ;
 exe hello2 : hello.cpp ;
 explicit hello2 ;
 """)
 
-t.write("hello.cpp", """
-int main() {}
-""")
+t.write("hello.cpp", "int main() {}\n")
 
 t.run_build_system()
 t.ignore("*.tds")
@@ -24,7 +22,7 @@
     [".exe", ".obj"])
 t.expect_nothing_more()
 
-t.run_build_system("hello2")
+t.run_build_system(["hello2"])
 t.expect_addition("bin/$toolset/debug/hello2.exe")
 
 t.rm(".")
@@ -32,7 +30,7 @@
 
 # Test that 'explicit' used in a helper rule applies to the current project, and
 # not to the Jamfile where the helper rule is defined.
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 rule myinstall ( name : target )
 {
     install $(name)-bin : $(target) ;
@@ -41,19 +39,15 @@
 }
 """)
 
-t.write("sub/a.cpp", """
-""")
-
-t.write("sub/jamfile.jam", """
-myinstall dist : a.cpp ;
-""")
+t.write("sub/a.cpp", "\n")
+t.write("sub/jamfile.jam", "myinstall dist : a.cpp ;")
 
 t.run_build_system(subdir="sub")
 t.expect_addition("sub/dist-bin/a.cpp")
 
 t.rm("sub/dist-bin")
 
-t.write("sub/jamfile.jam", """
+t.write("sub/jamfile.jam", """\
 myinstall dist : a.cpp ;
 explicit dist ;
 """)

Modified: branches/release/tools/build/v2/test/free_features_request.py
==============================================================================
--- branches/release/tools/build/v2/test/free_features_request.py (original)
+++ branches/release/tools/build/v2/test/free_features_request.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,26 +5,26 @@
 # accompanying file LICENSE_1_0.txt or copy at
 # http://www.boost.org/LICENSE_1_0.txt)
 
-# Tests that a free feature specified on the command line applies to all targets
-# ever built.
+# Tests that a free feature specified on the command line applies to all
+# targets ever built.
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 exe hello : hello.cpp foo ;
 lib foo : foo.cpp ;
 """)
 
-t.write("hello.cpp", """
+t.write("hello.cpp", """\
 extern void foo();
 #ifdef FOO
 int main() { foo(); }
 #endif
 """)
 
-t.write("foo.cpp", """
+t.write("foo.cpp", """\
 #ifdef FOO
 #ifdef _WIN32
 __declspec(dllexport)
@@ -35,7 +35,7 @@
 
 # If FOO is not defined when compiling the 'foo' target, we will get a link
 # error at this point.
-t.run_build_system("hello define=FOO")
+t.run_build_system(["hello", "define=FOO"])
 
 t.expect_addition("bin/$toolset/debug/hello.exe")
 

Modified: branches/release/tools/build/v2/test/gcc_runtime.py
==============================================================================
--- branches/release/tools/build/v2/test/gcc_runtime.py (original)
+++ branches/release/tools/build/v2/test/gcc_runtime.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,32 +2,27 @@
 
 # Copyright 2004 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
-# Tests that on gcc, we correctly report problem when static runtime is
+# Tests that on gcc, we correctly report a problem when static runtime is
 # requested for building a shared library.
 
 import BoostBuild
-import string
 
 t = BoostBuild.Tester()
+t.write("jamroot.jam", "lib hello : hello.cpp ;")
+t.write("hello.cpp", "int main() {}\n")
 
-# Create the needed files.
-t.write("jamroot.jam", "")
-
-t.write("jamfile.jam", """
-lib hello : hello.cpp ;
-""")
-
-t.write("hello.cpp", """
-int main() { }
-""")
-
-t.run_build_system("runtime-link=static")
-t.fail_test(string.find(t.stdout(),
- "On gcc, DLL can't be build with '<runtime-link>static'") == -1)
-
-t.run_build_system("link=static runtime-link=static")
-t.expect_addition("bin/$toolset/debug/link-static/runtime-link-static/hello.lib")
+t.run_build_system(["runtime-link=static"])
+t.expect_output_lines("warning: On gcc, DLLs can not be built with "
+ "'<runtime-link>static'.")
+t.expect_nothing_more()
+
+t.run_build_system(["link=static", "runtime-link=static"])
+binFolder = "bin/$toolset/debug/link-static/runtime-link-static"
+t.expect_addition("%s/hello.obj" % binFolder)
+t.expect_addition("%s/hello.lib" % binFolder)
+t.expect_nothing_more()
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/generator_selection.py
==============================================================================
--- branches/release/tools/build/v2/test/generator_selection.py (original)
+++ branches/release/tools/build/v2/test/generator_selection.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,57 +1,65 @@
 #!/usr/bin/python
 
-# Copyright 2008 Jurko Gospodnetic
+# Copyright 2008, 2012 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Tests that generators get selected correctly.
+#
+# We do not use the internal C++-compiler CPP --> OBJ generator to avoid
+# problems with specific compilers or their configurations, e.g. IBM's AIX test
+# runner 'AIX Version 5.3 TL7 SP5 (5300-07-05-0831)' using the 'IBM XL C/C++
+# for AIX, V12.1 (Version: 12.01.0000.0000)' reporting errors when run with a
+# source file whose suffix is not '.cpp'.
 
 import BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # test_generator_added_after_already_building_a_target_of_its_target_type()
 # -------------------------------------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_generator_added_after_already_building_a_target_of_its_target_type():
- """Regression test for a Boost Build bug causing it to not use a generator
- if it got added after already building a targer of its target type.
     """
+ Regression test for a Boost Build bug causing it to not use a generator
+ if it got added after already building a target of its target type.
 
+ """
     t = BoostBuild.Tester()
 
     t.write("dummy.cpp", "void f() {}\n")
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
+import common ;
+import generators ;
+import type ;
+type.register MY_OBJ : my_obj ;
+generators.register-standard common.copy : CPP : MY_OBJ ;
+
 # Building this dummy target must not cause a later defined CPP target type
 # generator not to be recognized as viable.
-obj dummy : dummy.cpp ;
+my-obj dummy : dummy.cpp ;
 alias the-other-obj : Other//other-obj ;
 """)
 
     t.write("Other/source.extension", "A dummy source file.")
 
- t.write("Other/mygen.jam", """
+ t.write("Other/mygen.jam", """\
+import common ;
 import generators ;
-import os ;
 import type ;
 type.register MY_TYPE : extension ;
-generators.register-standard mygen.generate-a-cpp-file : MY_TYPE : CPP ;
+generators.register-standard $(__name__).generate-a-cpp-file : MY_TYPE : CPP ;
 rule generate-a-cpp-file { ECHO Generating a CPP file... ; }
-if [ os.name ] = NT
-{
- actions generate-a-cpp-file { echo void g() {} > "$(<)" }
-}
-else
-{
- actions generate-a-cpp-file { echo "void g() {}" > "$(<)" }
-}
+CREATE-FILE = [ common.file-creation-command ] ;
+actions generate-a-cpp-file { $(CREATE-FILE) "$(<)" }
 """)
 
- t.write("Other/mygen.py", """
+ t.write("Other/mygen.py", """\
 import b2.build.generators as generators
 import b2.build.type as type
 
@@ -59,7 +67,6 @@
 
 import os
 
-
 type.register('MY_TYPE', ['extension'])
 generators.register_standard('mygen.generate-a-cpp-file', ['MY_TYPE'], ['CPP'])
 if os.name == 'nt':
@@ -69,72 +76,82 @@
 def f(*args):
     print "Generating a CPP file..."
 
-get_manager().engine().register_action("mygen.generate-a-cpp-file",
- action, function=f)
+get_manager().engine().register_action("mygen.generate-a-cpp-file", action,
+ function=f)
 """)
 
- t.write("Other/jamfile.jam", """
+ t.write("Other/jamfile.jam", """\
 import mygen ;
-obj other-obj : source.extension ;
+my-obj other-obj : source.extension ;
 """)
 
     t.run_build_system()
- t.expect_output_line("Generating a CPP file...")
- t.expect_addition("bin/$toolset/debug/dummy.obj")
- t.expect_addition("Other/bin/$toolset/debug/other-obj.obj")
+ t.expect_output_lines("Generating a CPP file...")
+ t.expect_addition("bin/$toolset/debug/dummy.my_obj")
+ t.expect_addition("Other/bin/$toolset/debug/other-obj.cpp")
+ t.expect_addition("Other/bin/$toolset/debug/other-obj.my_obj")
+ t.expect_nothing_more()
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # test_using_a_derived_source_type_created_after_generator_already_used()
 # -----------------------------------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_using_a_derived_source_type_created_after_generator_already_used():
- """Regression test for a Boost Build bug causing it to not use a generator
+ """
+ Regression test for a Boost Build bug causing it to not use a generator
     with a source type derived from one of the generator's sources but created
     only after already using the generateor.
- """
 
+ """
     t = BoostBuild.Tester()
 
- t.write("dummy.cpp", "void f() {}\n")
+ t.write("dummy.xxx", "Hello. My name is Peter Pan.\n")
+
+ t.write("jamroot.jam", """\
+import common ;
+import generators ;
+import type ;
+type.register XXX : xxx ;
+type.register YYY : yyy ;
+generators.register-standard common.copy : XXX : YYY ;
 
- t.write("jamroot.jam", """
-# Building this dummy target must not cause a later defined UNGA_CPP target type
-# not to be recognized as a viable source type for building OBJ targets.
-obj dummy : dummy.cpp ;
-alias the-test-output : Other//other-obj ;
+# Building this dummy target must not cause a later defined XXX2 target type not
+# to be recognized as a viable source type for building YYY targets.
+yyy dummy : dummy.xxx ;
+alias the-test-output : Other//other ;
 """)
 
- t.write("Other/source.unga_cpp", "void g() {}\n")
+ t.write("Other/source.xxx2", "Hello. My name is Tinkerbell.\n")
 
- t.write("Other/jamfile.jam", """
+ t.write("Other/jamfile.jam", """\
 import type ;
-type.register UNGA_CPP : unga_cpp : CPP ;
-# We are careful not to do anything between defining our new UNGA_CPP target
-# type and using the CPP --> OBJ generator that could potentially cover the
-# Boost Build bug by clearing its internal viable source target type state.
-obj other-obj : source.unga_cpp ;
+type.register XXX2 : xxx2 : XXX ;
+# We are careful not to do anything between defining our new XXX2 target type
+# and using the XXX --> YYY generator that could potentially cover the Boost
+# Build bug by clearing its internal viable source target type state.
+yyy other : source.xxx2 ;
 """)
 
     t.run_build_system()
- t.expect_addition("bin/$toolset/debug/dummy.obj")
- t.expect_addition("Other/bin/$toolset/debug/other-obj.obj")
+ t.expect_addition("bin/$toolset/debug/dummy.yyy")
+ t.expect_addition("Other/bin/$toolset/debug/other.yyy")
     t.expect_nothing_more()
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
 test_generator_added_after_already_building_a_target_of_its_target_type()
 test_using_a_derived_source_type_created_after_generator_already_used()

Modified: branches/release/tools/build/v2/test/generators_test.py
==============================================================================
--- branches/release/tools/build/v2/test/generators_test.py (original)
+++ branches/release/tools/build/v2/test/generators_test.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,30 +1,433 @@
 #!/usr/bin/python
 
-# Copyright 2003 Dave Abrahams
-# Copyright 2002, 2003, 2005 Vladimir Prus
+# Copyright 2002, 2003 Dave Abrahams
+# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
+# Copyright 2012 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
+import re
 
-t = BoostBuild.Tester()
 
-t.set_tree("generators-test")
+def test_basic():
+ t = BoostBuild.Tester(pass_d0=False)
+ __write_appender(t, "appender.jam")
+ t.write("a.cpp", "")
+ t.write("b.cxx", "")
+ t.write("c.tui", "")
+ t.write("d.wd", "")
+ t.write("e.cpp", "")
+ t.write("x.l", "")
+ t.write("y.x_pro", "")
+ t.write("z.cpp", "")
+ t.write("lib/c.cpp", "int bar() { return 0; }\n")
+ t.write("lib/jamfile.jam", "my-lib auxilliary : c.cpp ;")
+ t.write("jamroot.jam",
+r"""import appender ;
 
-t.run_build_system()
+import "class" : new ;
+import generators ;
+import type ;
 
-t.expect_addition( "bin/$toolset/debug/" * BoostBuild.List( "a.obj b.obj c.h "
- + "c.cpp c.obj d_parser.whl d_lexer.dlp d_parser.cpp d_lexer.cpp "
- + "d_parser.lr0 d_parser.h d_parser_symbols.h x.c x.obj y.x1 y.x2 y.cpp "
- + "y.obj e.marked_cpp e.positions e.target_cpp e.obj"))
-t.expect_addition("bin/$toolset/debug/a.exe")
-t.expect_addition(["lib/bin/$toolset/debug/c.obj",
- "lib/bin/$toolset/debug/auxilliary.lib"])
 
-t.run_build_system(subdir='lib')
-t.expect_addition(["lib/bin/$toolset/debug/auxilliary2.dll"])
+################################################################################
+#
+# We use our own custom EXE, LIB & OBJ target generators as using the regular
+# ones would force us to have to deal with different compiler/linker specific
+# 'features' that really have nothing to do with this test. For example, IBM XL
+# C/C++ for AIX, V12.1 (Version: 12.01.0000.0000) compiler exits with a non-zero
+# exit code and thus fails our build when run with a source file using an
+# unknown suffix like '.marked_cpp'.
+#
+################################################################################
 
-t.run_build_system(subdir='lib', extra_args="link=static")
-t.expect_addition(["lib/bin/$toolset/debug/link-static/auxilliary2.lib"])
+type.register MY_EXE : my_exe ;
+type.register MY_LIB : my_lib ;
+type.register MY_OBJ : my_obj ;
 
-t.cleanup()
+appender.register compile-c : C : MY_OBJ ;
+appender.register compile-cpp : CPP : MY_OBJ ;
+appender.register link-lib composing : MY_OBJ : MY_LIB ;
+appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ;
+
+
+################################################################################
+#
+# LEX --> C
+#
+################################################################################
+
+type.register LEX : l ;
+
+appender.register lex-to-c : LEX : C ;
+
+
+################################################################################
+#
+# /--> tUI_H --\
+# tUI --< >--> CPP
+# \------------/
+#
+################################################################################
+
+type.register tUI : tui ;
+type.register tUI_H : tui_h ;
+
+appender.register ui-to-cpp : tUI tUI_H : CPP ;
+appender.register ui-to-h : tUI : tUI_H ;
+
+
+################################################################################
+#
+# /--> X1 --\
+# X_PRO --< >--> CPP
+# \--> X2 --/
+#
+################################################################################
+
+type.register X1 : x1 ;
+type.register X2 : x2 ;
+type.register X_PRO : x_pro ;
+
+appender.register x1-x2-to-cpp : X1 X2 : CPP ;
+appender.register x-pro-to-x1-x2 : X_PRO : X1 X2 ;
+
+
+################################################################################
+#
+# When the main target type is NM_EXE, build OBJ from CPP-MARKED and not from
+# anything else, e.g. directly from CPP.
+#
+################################################################################
+
+type.register CPP_MARKED : marked_cpp : CPP ;
+type.register POSITIONS : positions ;
+type.register NM.TARGET.CPP : target_cpp : CPP ;
+type.register NM_EXE : : MY_EXE ;
+
+appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ;
+appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ;
+
+class nm::target::cpp-obj-generator : generator
+{
+ rule __init__ ( id )
+ {
+ generator.__init__ $(id) : NM.TARGET.CPP : MY_OBJ ;
+ generator.set-rule-name appender.appender ;
+ }
+
+ rule requirements ( )
+ {
+ return <main-target-type>NM_EXE ;
+ }
+
+ rule run ( project name ? : properties * : source : multiple ? )
+ {
+ if [ $(source).type ] = CPP
+ {
+ local converted = [ generators.construct $(project) : NM.TARGET.CPP
+ : $(properties) : $(source) ] ;
+ if $(converted)
+ {
+ return [ generators.construct $(project) : MY_OBJ :
+ $(properties) : $(converted[2]) ] ;
+ }
+ }
+ }
+}
+generators.register [ new nm::target::cpp-obj-generator target-obj ] ;
+generators.override target-obj : all ;
+
+
+################################################################################
+#
+# A more complex test case scenario with the following generators:
+# 1. WHL --> CPP, WHL_LR0, H, H(%_symbols)
+# 2. DLP --> CPP
+# 3. WD --> WHL(%_parser) DLP(%_lexer)
+# 4. A custom generator of higher priority than generators 1. & 2. that helps
+# disambiguate between them when generating CPP files from WHL and DLP
+# sources.
+#
+################################################################################
+
+type.register WHL : whl ;
+type.register DLP : dlp ;
+type.register WHL_LR0 : lr0 ;
+type.register WD : wd ;
+
+local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H
+ H(%_symbols) ] ;
+local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ;
+appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ;
+
+class wd-to-cpp : generator
+{
+ rule __init__ ( id : sources * : targets * )
+ {
+ generator.__init__ $(id) : $(sources) : $(targets) ;
+ }
+
+ rule run ( project name ? : property-set : source )
+ {
+ local new-sources = $(source) ;
+ if ! [ $(source).type ] in WHL DLP
+ {
+ local r1 = [ generators.construct $(project) $(name) : WHL :
+ $(property-set) : $(source) ] ;
+ local r2 = [ generators.construct $(project) $(name) : DLP :
+ $(property-set) : $(source) ] ;
+ new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ;
+ }
+
+ local result ;
+ for local i in $(new-sources)
+ {
+ local t = [ generators.construct $(project) $(name) : CPP :
+ $(property-set) : $(i) ] ;
+ result += $(t[2-]) ;
+ }
+ return $(result) ;
+ }
+}
+generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ;
+generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ;
+generators.register [ new wd-to-cpp $(__name__).wd-to-cpp : : CPP ] ;
+
+
+################################################################################
+#
+# Declare build targets.
+#
+################################################################################
+
+# This should not cause two CPP --> MY_OBJ constructions for a.cpp or b.cpp.
+my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ;
+my-exe f : a.cpp b.cxx obj_1 obj_2 lib//auxilliary ;
+
+# This should cause two CPP --> MY_OBJ constructions for z.cpp.
+my-obj obj_1 : z.cpp ;
+my-obj obj_2 : z.cpp ;
+
+nm-exe e : e.cpp ;
+""")
+
+ t.run_build_system()
+ t.expect_addition("bin/$toolset/debug/" * BoostBuild.List("a.my_exe "
+ "a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp "
+ "d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h "
+ "d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp "
+ "y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe "
+ "f.my_exe obj_1.my_obj obj_2.my_obj"))
+ t.expect_addition("lib/bin/$toolset/debug/" * BoostBuild.List("c.my_obj "
+ "auxilliary.my_lib"))
+ t.expect_nothing_more()
+
+ folder = "bin/$toolset/debug"
+ t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'")
+ t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'")
+ t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'")
+
+ lines = t.stdout().splitlines()
+ source_lines = [x for x in lines if re.match("^ Sources: '", x)]
+ if not __match_count_is(source_lines, "'z.cpp'", 2):
+ BoostBuild.annotation("failure", "z.cpp must be compiled exactly "
+ "twice.")
+ t.fail_test(1)
+ if not __match_count_is(source_lines, "'a.cpp'", 1):
+ BoostBuild.annotation("failure", "a.cpp must be compiled exactly "
+ "once.")
+ t.fail_test(1)
+ t.cleanup()
+
+
+def test_generated_target_names():
+ """
+ Test generator generated target names. Unless given explicitly, target
+ names should be determined based on their specified source names. All
+ sources for generating a target need to have matching names in order for
+ Boost Build to be able to implicitly determine the target's name.
+
+ We use the following target generation structure with differently named
+ BBX targets:
+ /---> BB1 ---\
+ AAA --<----> BB2 ---->--> CCC --(composing)--> DDD
+ \---> BB3 ---/
+
+ The extra generator at the end is needed because generating a top-level
+ CCC target directly would requires us to explicitly specify a name for it.
+ The extra generator needs to be composing in order not to explicitly
+ request a specific name for its CCC source target based on its own target
+ name.
+
+ We also check for a regression where only the first two sources were
+ checked to see if their names match. Note that we need to try out all file
+ renaming combinations as we do not know what ordering Boost Build is going
+ to use when passing in those files as generator sources.
+
+ """
+ jamfile_template = """\
+import type ;
+type.register AAA : _a ;
+type.register BB1 : _b1 ;
+type.register BB2 : _b2 ;
+type.register BB3 : _b3 ;
+type.register CCC : _c ;
+type.register DDD : _d ;
+
+import appender ;
+appender.register aaa-to-bbX : AAA : BB1%s BB2%s BB3%s ;
+appender.register bbX-to-ccc : BB1 BB2 BB3 : CCC ;
+appender.register ccc-to-ddd composing : CCC : DDD ;
+
+ddd _xxx : _xxx._a ;
+"""
+
+ t = BoostBuild.Tester(pass_d0=False)
+ __write_appender(t, "appender.jam")
+ t.write("_xxx._a", "")
+
+ def test_one(t, rename1, rename2, rename3, status):
+ def f(rename):
+ if rename: return "(%_x)"
+ return ""
+
+ jamfile = jamfile_template % (f(rename1), f(rename2), f(rename3))
+ t.write("jamroot.jam", jamfile, wait=False)
+
+ # Remove any preexisting targets left over from a previous test run
+ # so we do not have to be careful about tracking which files have been
+ # newly added and which preexisting ones have only been modified.
+ t.rm("bin")
+
+ t.run_build_system(status=status)
+
+ if status:
+ t.expect_output_lines("*.bbX-to-ccc: source targets have "
+ "different names: cannot determine target name")
+ else:
+ def suffix(rename):
+ if rename: return "_x"
+ return ""
+ name = "bin/$toolset/debug/_xxx"
+ e = t.expect_addition
+ e("%s%s._b1" % (name, suffix(rename1)))
+ e("%s%s._b2" % (name, suffix(rename2)))
+ e("%s%s._b3" % (name, suffix(rename3)))
+ e("%s%s._c" % (name, suffix(rename1 and rename2 and rename3)))
+ e("%s._d" % name)
+ t.expect_nothing_more()
+
+ test_one(t, False, False, False, status=0)
+ test_one(t, True , False, False, status=1)
+ test_one(t, False, True , False, status=1)
+ test_one(t, False, False, True , status=1)
+ test_one(t, True , True , False, status=1)
+ test_one(t, True , False, True , status=1)
+ test_one(t, False, True , True , status=1)
+ test_one(t, True , True , True , status=0)
+ t.cleanup()
+
+
+def __match_count_is(lines, pattern, expected):
+ count = 0
+ for x in lines:
+ if re.search(pattern, x):
+ count += 1
+ if count > expected:
+ return False
+ return count == expected
+
+
+def __write_appender(t, name):
+ t.write(name,
+r"""# Copyright 2012 Jurko Gospodnetic
+# 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)
+
+# Support for registering test generators that construct their targets by
+# simply appending their given input data, e.g. list of sources & targets.
+
+import "class" : new ;
+import generators ;
+import modules ;
+import sequence ;
+
+rule register ( id composing ? : source-types + : target-types + )
+{
+ local caller-module = [ CALLER_MODULE ] ;
+ id = $(caller-module).$(id) ;
+ local g = [ new generator $(id) $(composing) : $(source-types) :
+ $(target-types) ] ;
+ $(g).set-rule-name $(__name__).appender ;
+ generators.register $(g) ;
+ return $(id) ;
+}
+
+if [ modules.peek : NT ]
+{
+ X = ")" ;
+ ECHO_CMD = (echo. ;
+}
+else
+{
+ X = \" ;
+ ECHO_CMD = "echo $(X)" ;
+}
+
+local appender-runs ;
+
+# We set up separate actions for building each target in order to avoid having
+# to iterate over them in action (i.e. shell) code. We have to be extra careful
+# though to achieve the exact same effect as if doing all the work in just one
+# action. Otherwise Boost Jam might, under some circumstances, run only some of
+# our actions. To achieve this we register a series of actions for all the
+# targets (since they all have the same target list - either all or none of them
+# get run independent of which target actually needs to get built), each
+# building only a single target. Since all our actions use the same targets, we
+# can not use 'on-target' parameters to pass data to a specific action so we
+# pass them using the second 'sources' parameter which our actions then know how
+# to interpret correctly. This works well since Boost Jam does not automatically
+# add dependency relations between specified action targets & sources and so the
+# second argument, even though most often used to pass in a list of sources, can
+# actually be used for passing in any type of information.
+rule appender ( targets + : sources + : properties * )
+{
+ appender-runs = [ CALC $(appender-runs:E=0) + 1 ] ;
+ local target-index = 0 ;
+ local target-count = [ sequence.length $(targets) ] ;
+ local original-targets ;
+ for t in $(targets)
+ {
+ target-index = [ CALC $(target-index) + 1 ] ;
+ local appender-run = $(appender-runs) ;
+ if $(targets[2])-defined
+ {
+ appender-run += [$(target-index)/$(target-count)] ;
+ }
+ append $(targets) : $(appender-run:J=" ") $(t) $(sources) ;
+ }
+}
+
+actions append
+{
+ $(ECHO_CMD)-------------------------------------------------$(X)
+ $(ECHO_CMD)Appender run: $(>[1])$(X)
+ $(ECHO_CMD)Appender run: $(>[1])$(X)>> "$(>[2])"
+ $(ECHO_CMD)Target group: $(<:J=' ')$(X)
+ $(ECHO_CMD)Target group: $(<:J=' ')$(X)>> "$(>[2])"
+ $(ECHO_CMD) Target: '$(>[2])'$(X)
+ $(ECHO_CMD) Target: '$(>[2])'$(X)>> "$(>[2])"
+ $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)
+ $(ECHO_CMD) Sources: '$(>[3-]:J=' ')'$(X)>> "$(>[2])"
+ $(ECHO_CMD)=================================================$(X)
+ $(ECHO_CMD)-------------------------------------------------$(X)>> "$(>[2])"
+}
+""")
+
+
+test_basic()
+test_generated_target_names()

Modified: branches/release/tools/build/v2/test/implicit_dependency.py
==============================================================================
--- branches/release/tools/build/v2/test/implicit_dependency.py (original)
+++ branches/release/tools/build/v2/test/implicit_dependency.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,7 +10,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 make a.h : : gen-header ;

Modified: branches/release/tools/build/v2/test/indirect_conditional.py
==============================================================================
--- branches/release/tools/build/v2/test/indirect_conditional.py (original)
+++ branches/release/tools/build/v2/test/indirect_conditional.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,17 +1,17 @@
 #!/usr/bin/python
 
-# Copyright (C) Vladimir Prus 2006.
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
+# Copyright (C) 2006. Vladimir Prus
+# 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 BoostBuild
 
-t = BoostBuild.Tester()
+def test_basic():
+ t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 exe a1 : a1.cpp : <conditional>@a1-rule ;
-
 rule a1-rule ( properties * )
 {
     if <variant>debug in $(properties)
@@ -22,7 +22,6 @@
 
 exe a2 : a2.cpp : <conditional>@$(__name__).a2-rule
     <variant>debug:<optimization>speed ;
-
 rule a2-rule ( properties * )
 {
     if <optimization>speed in $(properties)
@@ -31,9 +30,9 @@
     }
 }
 
-exe a3 : a3.cpp : <conditional>@$(__name__).a3-rule-1
+exe a3 : a3.cpp :
+ <conditional>@$(__name__).a3-rule-1
     <conditional>@$(__name__).a3-rule-2 ;
-
 rule a3-rule-1 ( properties * )
 {
     if <optimization>speed in $(properties)
@@ -41,7 +40,6 @@
         return <define>OK ;
     }
 }
-
 rule a3-rule-2 ( properties * )
 {
     if <variant>debug in $(properties)
@@ -51,28 +49,57 @@
 }
 """)
 
-t.write("a1.cpp", """
-#ifdef OK
-int main() {}
-#endif
-""")
+ t.write("a1.cpp", "#ifdef OK\nint main() {}\n#endif\n")
+ t.write("a2.cpp", "#ifdef OK\nint main() {}\n#endif\n")
+ t.write("a3.cpp", "#ifdef OK\nint main() {}\n#endif\n")
 
-t.write("a2.cpp", """
-#ifdef OK
-int main() {}
-#endif
-""")
+ t.run_build_system()
+
+ t.expect_addition("bin/$toolset/debug/a1.exe")
+ t.expect_addition("bin/$toolset/debug/optimization-speed/a2.exe")
+ t.expect_addition("bin/$toolset/debug/optimization-speed/a3.exe")
 
-t.write("a3.cpp", """
-#ifdef OK
-int main() {}
+ t.cleanup()
+
+
+def test_glob_in_indirect_conditional():
+ """
+ Regression test: project-rules.glob rule run from inside an indirect
+ conditional should report an error as it depends on the 'currently loaded
+ project' concept and indirect conditional rules get called only after all
+ the project modules have already finished loading.
+
+ """
+ t = BoostBuild.Tester(use_test_config=False)
+
+ t.write("jamroot.jam", """\
+use-project /library-example/foo : util/foo ;
+build-project app ;
+""")
+ t.write("app/app.cpp", "int main() {}\n");
+ t.write("app/jamfile.jam", "exe app : app.cpp /library-example/foo//bar ;")
+ t.write("util/foo/bar.cpp", """\
+#ifdef _WIN32
+__declspec(dllexport)
 #endif
+void foo() {}
 """)
+ t.write("util/foo/jamfile.jam", """\
+rule print-my-sources ( properties * )
+{
+ ECHO My sources: ;
+ ECHO [ glob *.cpp ] ;
+}
+lib bar : bar.cpp : <conditional>@print-my-sources ;
+""")
+
+ t.run_build_system(status=1)
+ t.expect_output_lines(["My sources:", "bar.cpp"], False)
+ t.expect_output_lines("error: Reference to the project currently being "
+ "loaded requested when there was no project module being loaded.")
 
-t.run_build_system()
+ t.cleanup()
 
-t.expect_addition("bin/$toolset/debug/a1.exe")
-t.expect_addition("bin/$toolset/debug/optimization-speed/a2.exe")
-t.expect_addition("bin/$toolset/debug/optimization-speed/a3.exe")
 
-t.cleanup()
+test_basic()
+test_glob_in_indirect_conditional()

Modified: branches/release/tools/build/v2/test/inherit_toolset.py
==============================================================================
--- branches/release/tools/build/v2/test/inherit_toolset.py (original)
+++ branches/release/tools/build/v2/test/inherit_toolset.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,10 +9,9 @@
 
 t = BoostBuild.Tester(pass_toolset=0)
 
-t.write("a.cpp", """
-""")
+t.write("a.cpp", "\n")
 
-t.write("yfc1.jam", """
+t.write("yfc1.jam", """\
 import feature ;
 import generators ;
 
@@ -26,7 +25,7 @@
 actions link { yfc1-link }
 """)
 
-t.write("yfc2.jam", """
+t.write("yfc2.jam", """\
 import feature ;
 import toolset ;
 
@@ -37,23 +36,16 @@
 actions link { yfc2-link }
 """)
 
-t.write("jamfile.jam", """
-exe a : a.cpp ;
-""")
+t.write("jamfile.jam", "exe a : a.cpp ;")
+t.write("jamroot.jam", "using yfc1 ;")
 
-t.write("jamroot.jam", """
-using yfc1 ;
-""")
-
-t.run_build_system("-n -d2 yfc1")
+t.run_build_system(["-n", "-d2", "yfc1"])
 t.fail_test(string.find(t.stdout(), "yfc1-link") == -1)
 
 # Make sure we do not have to explicitly 'use' yfc1.
-t.write("jamroot.jam", """
-using yfc2 ;
-""")
+t.write("jamroot.jam", "using yfc2 ;")
 
-t.run_build_system("-n -d2 yfc2")
+t.run_build_system(["-n", "-d2", "yfc2"])
 t.fail_test(string.find(t.stdout(), "yfc2-link") == -1)
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/inherited_dependency.py
==============================================================================
--- branches/release/tools/build/v2/test/inherited_dependency.py (original)
+++ branches/release/tools/build/v2/test/inherited_dependency.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,7 @@
 
 import BoostBuild
 
-tester = BoostBuild.Tester()
+tester = BoostBuild.Tester(use_test_config=False)
 
 
 ################################################################################

Modified: branches/release/tools/build/v2/test/inline.py
==============================================================================
--- branches/release/tools/build/v2/test/inline.py (original)
+++ branches/release/tools/build/v2/test/inline.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,27 +6,25 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 project : requirements <link>static ;
 exe a : a.cpp [ lib helper : helper.cpp ] ;
 """)
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 extern void helper();
 int main() {}
 """)
 
-t.write("helper.cpp", """
-void helper() {}
-""")
+t.write("helper.cpp", "void helper() {}\n")
 
 t.run_build_system()
 t.expect_addition("bin/$toolset/debug/link-static/a__helper.lib")
 t.rm("bin/$toolset/debug/link-static/a__helper.lib")
 
-t.run_build_system("a__helper")
+t.run_build_system(["a__helper"])
 t.expect_addition("bin/$toolset/debug/link-static/a__helper.lib")
 
 t.rm("bin")
@@ -34,7 +32,7 @@
 
 # Now check that inline targets with the same name but present in different
 # places are not confused between each other, and with top-level targets.
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 project : requirements <link>static ;
 exe a : a.cpp [ lib helper : helper.cpp ] ;
 exe a2 : a.cpp [ lib helper : helper.cpp ] ;
@@ -48,7 +46,7 @@
 
 # Check that the 'alias' target does not change the name of inline targets, and
 # that inline targets are explicit.
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 project : requirements <link>static ;
 alias a : [ lib helper : helper.cpp ] ;
 explicit a ;
@@ -58,7 +56,7 @@
 t.run_build_system()
 t.expect_nothing_more()
 
-t.run_build_system("a")
+t.run_build_system(["a"])
 t.expect_addition("bin/$toolset/debug/link-static/helper.lib")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/lib_source_property.py
==============================================================================
--- branches/release/tools/build/v2/test/lib_source_property.py (original)
+++ branches/release/tools/build/v2/test/lib_source_property.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,7 +11,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 lib a : : <source>a.cpp ;

Modified: branches/release/tools/build/v2/test/library_chain.py
==============================================================================
--- branches/release/tools/build/v2/test/library_chain.py (original)
+++ branches/release/tools/build/v2/test/library_chain.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,27 +8,26 @@
 # linking.
 
 import BoostBuild
-import string
 import os
+import string
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamfile.jam", """
-# Stage the binary, so that it will be relinked without hardcode-dll-paths. That
-# will chech that we pass correct -rpath-link, even if not passing -rpath.
+# Stage the binary, so that it will be relinked without hardcode-dll-paths.
+# That will check that we pass correct -rpath-link, even if not passing -rpath.
+t.write("jamfile.jam", """\
 stage dist : main ;
 exe main : main.cpp b ;
 """)
 
-t.write("main.cpp", """
+t.write("main.cpp", """\
 void foo();
 int main() { foo(); }
 """)
 
-t.write("jamroot.jam", """
-""")
+t.write("jamroot.jam", "")
 
-t.write("a/a.cpp", """
+t.write("a/a.cpp", """\
 void
 #if defined(_WIN32)
 __declspec(dllexport)
@@ -41,11 +40,9 @@
 geek() {}
 """)
 
-t.write("a/jamfile.jam", """
-lib a : a.cpp ;
-""")
+t.write("a/jamfile.jam", "lib a : a.cpp ;")
 
-t.write("b/b.cpp", """
+t.write("b/b.cpp", """\
 void geek();
 void
 #if defined(_WIN32)
@@ -54,32 +51,26 @@
 foo() { geek(); }
 """)
 
-t.write("b/jamfile.jam", """
-lib b : b.cpp ../a//a ;
-""")
+t.write("b/jamfile.jam", "lib b : b.cpp ../a//a ;")
 
-t.run_build_system("-d2", stderr=None)
+t.run_build_system(["-d2"], stderr=None)
 t.expect_addition("bin/$toolset/debug/main.exe")
 t.rm(["bin", "a/bin", "b/bin"])
 
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("bin/$toolset/debug/link-static/main.exe")
 t.rm(["bin", "a/bin", "b/bin"])
 
 
 # Check that <library> works for static linking.
-t.write("b/jamfile.jam", """
-lib b : b.cpp : <library>../a//a ;
-""")
+t.write("b/jamfile.jam", "lib b : b.cpp : <library>../a//a ;")
 
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("bin/$toolset/debug/link-static/main.exe")
 
 t.rm(["bin", "a/bin", "b/bin"])
 
-t.write("b/jamfile.jam", """
-lib b : b.cpp ../a//a/<link>shared : <link>static ;
-""")
+t.write("b/jamfile.jam", "lib b : b.cpp ../a//a/<link>shared : <link>static ;")
 
 t.run_build_system()
 t.expect_addition("bin/$toolset/debug/main.exe")
@@ -88,13 +79,13 @@
 
 
 # Test that putting a library in sources of a searched library works.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe main : main.cpp png ;
 lib png : z : <name>png ;
 lib z : : <name>zzz ;
 """)
 
-t.run_build_system("-a -d+2", status=None, stderr=None)
+t.run_build_system(["-a", "-d+2"], status=None, stderr=None)
 # Try to find the "zzz" string either in response file (for Windows compilers),
 # or in the standard output.
 rsp = t.adjust_names("bin/$toolset/debug/main.exe.rsp")[0]
@@ -110,13 +101,12 @@
 t.rm(".")
 
 t.write("jamroot.jam", "")
-
-t.write("a/jamfile.jam", """
+t.write("a/jamfile.jam", """\
 lib a : a.cpp ;
 install dist : a ;
 """)
 
-t.write("a/a.cpp", """
+t.write("a/a.cpp", """\
 #if defined(_WIN32)
 __declspec(dllexport)
 #endif
@@ -126,18 +116,16 @@
 t.run_build_system(subdir="a")
 t.expect_addition("a/dist/a.dll")
 
-if ( ( os.name == 'nt' ) or os.uname()[0].lower().startswith('cygwin') ) and \
- ( BoostBuild.get_toolset() != 'gcc' ):
- # This is windows import library -- we know the exact name.
+if ( os.name == 'nt' or os.uname()[0].lower().startswith('cygwin') ) and \
+ BoostBuild.get_toolset() != 'gcc':
+ # This is a Windows import library -- we know the exact name.
     file = "a/dist/a.lib"
 else:
- file = t.adjust_names(["a/dist/a.dll"])[0]
+ file = t.adjust_names("a/dist/a.dll")[0]
 
-t.write("b/jamfile.jam", """
-lib b : b.cpp ../%s ;
-""" % file)
+t.write("b/jamfile.jam", "lib b : b.cpp ../%s ;" % file)
 
-t.write("b/b.cpp", """
+t.write("b/b.cpp", """\
 #if defined(_WIN32)
 __declspec(dllimport)
 #endif
@@ -148,11 +136,9 @@
 void b() { a(); }
 """)
 
-t.write("jamroot.jam", """
-exe main : main.cpp b//b ;
-""")
+t.write("jamroot.jam", "exe main : main.cpp b//b ;")
 
-t.write("main.cpp", """
+t.write("main.cpp", """\
 #if defined(_WIN32)
 __declspec(dllimport)
 #endif

Modified: branches/release/tools/build/v2/test/library_order.py
==============================================================================
--- branches/release/tools/build/v2/test/library_order.py (original)
+++ branches/release/tools/build/v2/test/library_order.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,37 +4,41 @@
 # 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)
 
-# Test that on compilers sensitive to library order on linker's command line, we
-# generate the correct order.
+# Test that on compilers sensitive to library order on linker's command line,
+# we generate the correct order.
 
 import BoostBuild
-import string
 
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("a.cpp", """
+t.write("main.cpp", """\
+void a();
+int main() { a(); }
+""")
+
+t.write("a.cpp", """\
 void b();
 void a() { b(); }
 """)
 
-t.write("b.cpp", """
+t.write("b.cpp", """\
 void c();
 void b() { c(); }
 """)
 
-t.write("c.cpp", """
+t.write("c.cpp", """\
 void d();
 void c() { d(); }
 """)
 
-t.write("d.cpp", """
+t.write("d.cpp", """\
 void d() {}
 """)
 
-# The order of libraries in 'main' is crafted so that we get error unless we do
-# something about the order ourselves.
-t.write("jamfile.jam", """
+# The order of libraries in 'main' is crafted so that we get an error unless we
+# do something about the order ourselves.
+t.write("jamroot.jam", """\
 exe main : main.cpp libd libc libb liba ;
 lib libd : d.cpp ;
 lib libc : c.cpp : <link>static <use>libd ;
@@ -42,59 +46,49 @@
 lib liba : a.cpp : <use>libb ;
 """)
 
-t.write("main.cpp", """
-void a();
-int main() { a(); }
-""")
-
-t.write("jamroot.jam", """
-""")
-
-t.run_build_system("-d2")
+t.run_build_system(["-d2"])
 t.expect_addition("bin/$toolset/debug/main.exe")
 
 
 # Test the order between searched libraries.
-t.write("jamfile.jam", """
+t.write("jamroot.jam", """\
 exe main : main.cpp png z ;
 lib png : z : <name>png ;
 lib z : : <name>zzz ;
 """)
 
-t.run_build_system("-a -n -d+2")
-t.fail_test(string.find(t.stdout(), "png") > string.find(t.stdout(), "zzz"))
+t.run_build_system(["-a", "-n", "-d+2"])
+t.fail_test(t.stdout().find("png") > t.stdout().find("zzz"))
 
-t.write("jamfile.jam", """
+t.write("jamroot.jam", """\
 exe main : main.cpp png z ;
 lib png : : <name>png ;
 lib z : png : <name>zzz ;
 """)
 
-t.run_build_system("-a -n -d+2")
-t.fail_test(string.find(t.stdout(), "png") < string.find(t.stdout(), "zzz"))
+t.run_build_system(["-a", "-n", "-d+2"])
+t.fail_test(t.stdout().find("png") < t.stdout().find("zzz"))
 
 
 # Test the order between prebuilt libraries.
 t.write("first.a", "")
-
 t.write("second.a", "")
-
-t.write("jamfile.jam", """
+t.write("jamroot.jam", """\
 exe main : main.cpp first second ;
 lib first : second : <file>first.a ;
 lib second : : <file>second.a ;
 """)
 
-t.run_build_system("-a -n -d+2")
-t.fail_test(string.find(t.stdout(), "first") > string.find(t.stdout(), "second"))
+t.run_build_system(["-a", "-n", "-d+2"])
+t.fail_test(t.stdout().find("first") > t.stdout().find("second"))
 
-t.write("jamfile.jam", """
+t.write("jamroot.jam", """
 exe main : main.cpp first second ;
 lib first : : <file>first.a ;
 lib second : first : <file>second.a ;
 """)
 
-t.run_build_system("-a -n -d+2")
-t.fail_test(string.find(t.stdout(), "first") < string.find(t.stdout(), "second"))
+t.run_build_system(["-a", "-n", "-d+2"])
+t.fail_test(t.stdout().find("first") < t.stdout().find("second"))
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/library_property.py
==============================================================================
--- branches/release/tools/build/v2/test/library_property.py (original)
+++ branches/release/tools/build/v2/test/library_property.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -15,7 +15,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 project : requirements <library>lib//x ;

Modified: branches/release/tools/build/v2/test/load_order.py
==============================================================================
--- branches/release/tools/build/v2/test/load_order.py (original)
+++ branches/release/tools/build/v2/test/load_order.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,31 +1,30 @@
 #!/usr/bin/python
 
 # Copyright 2004 Vladimir Prus.
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
+# 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)
 
 # Test that we load parent projects before loading children.
 
 import BoostBuild
-import string
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 use-project /child : child ;
 ECHO "Setting parent requirements" ;
 project : requirements <define>PASS_THE_TEST ;
 alias x : child//main ;
 """)
 
-t.write("child/jamfile.jam", """
+t.write("child/jamfile.jam", """\
 ECHO "Setting child requirements" ;
 project /child ;
 exe main : main.cpp ;
 """)
 
-t.write("child/main.cpp", """
+t.write("child/main.cpp", """\
 #if defined(PASS_THE_TEST)
 int main() {}
 #endif
@@ -34,25 +33,16 @@
 t.run_build_system()
 
 t.expect_addition("child/bin/$toolset/debug/main.exe")
-t.fail_test(string.find(t.stdout(), "Setting child requirements") <
- string.find(t.stdout(), "Setting parent requirements"))
+t.fail_test(t.stdout().find("Setting child requirements") < t.stdout().find(
+ "Setting parent requirements"))
 
 
 # Regression test: parent requirements were ignored in some cases.
 t.rm(".")
-t.write("jamroot.jam", """
-build-project src ;
-""")
-
-t.write("src/jamfile.jam", """
-project : requirements <define>EVERYTHING_OK ;
-""")
-
-t.write("src/app/jamfile.jam", """
-exe test : test.cpp ;
-""")
-
-t.write("src/app/test.cpp", """
+t.write("jamroot.jam", "build-project src ;")
+t.write("src/jamfile.jam", "project : requirements <define>EVERYTHING_OK ;")
+t.write("src/app/jamfile.jam", "exe test : test.cpp ;")
+t.write("src/app/test.cpp", """\
 #ifdef EVERYTHING_OK
 int main() {}
 #endif
@@ -61,28 +51,21 @@
 t.run_build_system(subdir="src/app")
 t.expect_addition("src/app/bin/$toolset/debug/test.exe")
 
+
 # child/child2 used to be loaded before child
 t.rm(".")
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 use-project /child/child2 : child/child2 ;
 rule parent-rule ( )
 {
   ECHO "Running parent-rule" ;
 }
 """)
-
-t.write("child/jamfile.jam", """
-""")
-
-t.write("child/child1/jamfile.jam", """
-""")
-
-t.write("child/child2/jamfile.jam", """
-parent-rule ;
-""")
-
+t.write("child/jamfile.jam", "")
+t.write("child/child1/jamfile.jam", "")
+t.write("child/child2/jamfile.jam", "parent-rule ;")
 
 t.run_build_system(subdir="child/child1")
-t.expect_output_line("Running parent-rule")
+t.expect_output_lines("Running parent-rule")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/loop.py
==============================================================================
--- branches/release/tools/build/v2/test/loop.py (original)
+++ branches/release/tools/build/v2/test/loop.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,16 +9,15 @@
 
 t = BoostBuild.Tester()
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 lib main : main.cpp l ;
 lib l : l.cpp main ;
 """)
 
 t.write("main.cpp", "")
-
 t.write("l.cpp", "")
 
-t.run_build_system("--no-error-backtrace", status=1)
+t.run_build_system(["--no-error-backtrace"], status=1)
 t.fail_test(string.find(t.stdout(),
     "error: Recursion in main target references") == -1)
 

Modified: branches/release/tools/build/v2/test/make_rule.py
==============================================================================
--- branches/release/tools/build/v2/test/make_rule.py (original)
+++ branches/release/tools/build/v2/test/make_rule.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,7 +12,7 @@
 
 t = BoostBuild.Tester(pass_toolset=1)
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 import feature ;
 feature.feature test_feature : : free ;
 
@@ -35,24 +35,20 @@
 # Regression test. Make sure that if a main target is requested two times, and
 # build requests differ only in incidental properties, the main target is
 # created only once. The bug was discovered by Kirill Lapshin.
-t.write("jamroot.jam", """
-# Make sure that incidental property does not cause second creation of
-# 'hello1.cpp'.
+t.write("jamroot.jam", """\
 exe a : dir//hello1.cpp ;
 exe b : dir//hello1.cpp/<hardcode-dll-paths>true ;
 """)
 
-t.write("dir/jamfile.jam", """
+t.write("dir/jamfile.jam", """\
 import common ;
 make hello1.cpp : hello.cpp : common.copy ;
 """)
 
-t.write("dir/hello.cpp", """
-int main() {}
-""")
+t.write("dir/hello.cpp", "int main() {}\n")
 
 # Show only action names.
-t.run_build_system("-d1 -n")
+t.run_build_system(["-d1", "-n"])
 t.fail_test(t.stdout().count("copy") != 1)
 
 t.cleanup()

Copied: branches/release/tools/build/v2/test/message.py (from r80981, /trunk/tools/build/v2/test/message.py)
==============================================================================
--- /trunk/tools/build/v2/test/message.py (original)
+++ branches/release/tools/build/v2/test/message.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,7 +10,7 @@
 import BoostBuild
 
 # Create a temporary working directory.
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("Jamroot.jam", """
 project
@@ -32,7 +32,7 @@
 t.run_build_system(["test"], stdout="""Hello World!
 """)
 
-t.expect_addition("bin/$toolset/link-static/test.o")
+t.expect_addition("bin/$toolset/link-static/test.obj")
 t.expect_nothing_more()
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/module_actions.py
==============================================================================
--- branches/release/tools/build/v2/test/module_actions.py (original)
+++ branches/release/tools/build/v2/test/module_actions.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,53 +1,105 @@
 #!/usr/bin/python
 
-# Copyright 2003 Dave Abrahams
-# Copyright 2006 Rene Rivera
-# Copyright 2003 Vladimir Prus
-# 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)
+# Copyright 2003 Dave Abrahams
+# Copyright 2006 Rene Rivera
+# Copyright 2003 Vladimir Prus
+# 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)
+
+# Demonstration that module variables have the correct effect in actions.
 
 import BoostBuild
 import os
 import re
 
-spaces_re = re.compile("\ \ +")
-trailing_spaces_re = re.compile("\ +\n")
-
-t = BoostBuild.Tester("-d+1", pass_toolset=0)
-
-t.set_tree('module-actions')
+t = BoostBuild.Tester(["-d+1"], pass_toolset=0)
 
-# Note that the following string contains some trailing spaces that should not
-# be removed.
-expected_output = """...found 4 targets...
-...updating 3 targets...
-A.act t1
-A.act t1: X1-t1
-B.act t1
-B.act t1: X1-t1 X2-B
-act t1
-act t1: X1-t1 X2-global X3-global
-A.act t2
-A.act t2: X1-A X2-t2
-B.act t2
-B.act t2: X2-t2
-act t2
-act t2: X1-global X2-t2 X3-global
-A.act t3
-A.act t3: X1-A X3-t3
-B.act t3
-B.act t3: X2-B X3-t3
-act t3
-act t3: X1-global X2-global X3-t3
-...updated 3 targets...
-"""
+t.write("boost-build.jam", "boost-build . ;")
+t.write("bootstrap.jam", """\
+# Top-level rule causing a target to be built by invoking the specified action.
+rule make ( target : sources * : act )
+{
+ DEPENDS all : $(target) ;
+ DEPENDS $(target) : $(sources) ;
+ $(act) $(target) : $(sources) ;
+}
+
+X1 = X1-global ;
+X2 = X2-global ;
+X3 = X3-global ;
+
+module A
+{
+ X1 = X1-A ;
+
+ rule act ( target )
+ {
+ NOTFILE $(target) ;
+ ALWAYS $(target) ;
+ }
+
+ actions act { echo A.act $(<): $(X1) $(X2) $(X3) }
+
+ make t1 : : A.act ;
+ make t2 : : A.act ;
+ make t3 : : A.act ;
+}
+
+module B
+{
+ X2 = X2-B ;
+
+ actions act { echo B.act $(<): $(X1) $(X2) $(X3) }
+
+ make t1 : : B.act ;
+ make t2 : : B.act ;
+ make t3 : : B.act ;
+}
+
+actions act { echo act $(<): $(X1) $(X2) $(X3) }
+
+make t1 : : act ;
+make t2 : : act ;
+make t3 : : act ;
+
+X1 on t1 = X1-t1 ;
+X2 on t2 = X2-t2 ;
+X3 on t3 = X3-t3 ;
+
+DEPENDS all : t1 t2 t3 ;
+""")
+
+expected_lines = [
+ "...found 4 targets...",
+ "...updating 3 targets...",
+ "A.act t1",
+ "A.act t1: X1-t1 ",
+ "B.act t1",
+ "B.act t1: X1-t1 X2-B ",
+ "act t1",
+ "act t1: X1-t1 X2-global X3-global ",
+ "A.act t2",
+ "A.act t2: X1-A X2-t2 ",
+ "B.act t2",
+ "B.act t2: X2-t2 ",
+ "act t2",
+ "act t2: X1-global X2-t2 X3-global ",
+ "A.act t3",
+ "A.act t3: X1-A X3-t3 ",
+ "B.act t3",
+ "B.act t3: X2-B X3-t3 ",
+ "act t3",
+ "act t3: X1-global X2-global X3-t3 ",
+ "...updated 3 targets...",
+ ""]
 
-# On Unixes, call to 'echo 1 2 3' produces '1 2 3' (note the spacing)
-# Accomodate for that fact.
+# Accommodate for the fact that on Unixes, a call to 'echo 1 2 3 '
+# produces '1 2 3' (note the spacing).
 if os.name != 'nt':
- expected_output = re.sub(spaces_re, " ", expected_output)
- expected_output = re.sub(trailing_spaces_re, "\n", expected_output)
+ expected_lines = [re.sub(" +", " ", x.rstrip()) for x in expected_lines]
 
-t.run_build_system(stdout=expected_output)
+t.run_build_system()
+t.expect_output_lines(expected_lines)
 t.expect_nothing_more()
 t.cleanup()

Modified: branches/release/tools/build/v2/test/ndebug.py
==============================================================================
--- branches/release/tools/build/v2/test/ndebug.py (original)
+++ branches/release/tools/build/v2/test/ndebug.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,30 +10,24 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
-exe hello : hello.cpp lib//lib1 ;
-""")
-
-t.write("hello.cpp", """
+t.write("jamroot.jam", "exe hello : hello.cpp lib//lib1 ;")
+t.write("hello.cpp", """\
 #ifdef NDEBUG
 void foo();
 int main() { foo(); }
 #endif
 """)
-
-t.write("lib/jamfile.jam", """
-lib lib1 : lib1.cpp ;
-""")
-t.write("lib/lib1.cpp", """
+t.write("lib/jamfile.jam", "lib lib1 : lib1.cpp ;")
+t.write("lib/lib1.cpp", """\
 #ifdef NDEBUG
 void foo() {}
 #endif
 """)
 
 # 'release' builds should get the NDEBUG define. We use static linking to avoid
-# messing with imports/exports on windows.
-t.run_build_system("link=static release")
+# messing with imports/exports on Windows.
+t.run_build_system(["link=static", "release"])
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/no_type.py
==============================================================================
--- branches/release/tools/build/v2/test/no_type.py (original)
+++ branches/release/tools/build/v2/test/no_type.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,8 +1,8 @@
 #!/usr/bin/python
 
-# Copyright 2002 Vladimir Prus
-# 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)
+# Copyright 2002 Vladimir Prus
+# 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)
 
 # Test that we cannot specify targets of unknown type as sources. This is based
 # on the fact that Unix 'ar' will happily consume just about anything.
@@ -11,11 +11,7 @@
 
 t = BoostBuild.Tester()
 
-t.write("jamroot.jam", """
-import gcc ;
-static-lib a : a.foo ;
-""")
-
+t.write("jamroot.jam", "static-lib a : a.foo ;")
 t.write("a.foo", "")
 
 t.run_build_system(status=1)

Modified: branches/release/tools/build/v2/test/notfile.py
==============================================================================
--- branches/release/tools/build/v2/test/notfile.py (original)
+++ branches/release/tools/build/v2/test/notfile.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,44 +1,36 @@
 #!/usr/bin/python
 
 # Copyright (C) Vladimir Prus 2005.
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
+# 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)
 
 # Basic tests for the 'notfile' rule.
 
 import BoostBuild
-import string
 import os
 
 t = BoostBuild.Tester()
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 import notfile ;
 notfile say : "echo hi" ;
-
 exe hello : hello.cpp ;
 notfile hello_valgrind : @valgrind : hello ;
-
-actions valgrind
-{
- valgrind $(>[1])
-}
+actions valgrind { valgrind $(>[1]) }
 """)
 
-t.write("hello.cpp", """
+t.write("hello.cpp", """\
 #include <iostream>
 int main() { std::cout << "Hello!\\n"; }
 """)
 
+t.run_build_system(["-n", "-d+2"])
 
-t.run_build_system("-n -d+2")
-
-t.fail_test(string.find(t.stdout(), "echo hi") == -1)
+t.fail_test(t.stdout().find("echo hi") == -1)
 
-name = t.adjust_names(["bin/$toolset/debug/hello.exe"])[0]
-name = apply(os.path.join, string.split(name, "/"));
-c = "valgrind *" + name
-t.expect_output_line(c)
+name = t.adjust_names("bin/$toolset/debug/hello.exe")[0]
+name = apply(os.path.join, name.split("/"));
+t.expect_output_lines(" valgrind *%s " % name)
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/ordered_include.py
==============================================================================
--- branches/release/tools/build/v2/test/ordered_include.py (original)
+++ branches/release/tools/build/v2/test/ordered_include.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,7 @@
 
 import BoostBuild
 
-tester = BoostBuild.Tester()
+tester = BoostBuild.Tester(use_test_config=False)
 
 tester.write("jamroot.jam", """
 obj test : test.cpp : <include>a&&b ;

Modified: branches/release/tools/build/v2/test/out_of_tree.py
==============================================================================
--- branches/release/tools/build/v2/test/out_of_tree.py (original)
+++ branches/release/tools/build/v2/test/out_of_tree.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,6 +1,6 @@
 #!/usr/bin/python
 
-# Copyright (C) FILL SOMETHING HERE 2005.
+# Copyright (C) Vladimir Prus 2005.
 # 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)
@@ -11,28 +11,18 @@
 import BoostBuild
 
 # Create a temporary working directory.
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Create the needed files.
-t.write("p1/jamroot.jam", """
-exe hello : hello.cpp ;
-""")
-
-t.write("p1/hello.cpp", """
-int main() {}
-""")
-
-t.write("p2/jamroot.jam", """
+t.write("p1/jamroot.jam", "exe hello : hello.cpp ;")
+t.write("p1/hello.cpp", "int main() {}\n")
+t.write("p2/jamroot.jam", """\
 exe hello2 : hello.cpp ;
 exe hello3 : hello.cpp ;
 """)
+t.write("p2/hello.cpp", "int main() {}\n")
 
-t.write("p2/hello.cpp", """
-int main() {}
-""")
-
-t.run_build_system("p1 p2//hello3")
-
+t.run_build_system(["p1", "p2//hello3"])
 t.expect_addition("p1/bin/$toolset/debug/hello.exe")
 t.expect_addition("p2/bin/$toolset/debug/hello3.exe")
 

Modified: branches/release/tools/build/v2/test/path_features.py
==============================================================================
--- branches/release/tools/build/v2/test/path_features.py (original)
+++ branches/release/tools/build/v2/test/path_features.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,85 +1,152 @@
 #!/usr/bin/python
 
-# Copyright 2003 Dave Abrahams
-# Copyright 2002, 2003, 2004 Vladimir Prus
-# 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)
+# Copyright 2003 Dave Abrahams
+# Copyright 2002, 2003, 2004 Vladimir Prus
+# 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 BoostBuild
 
-t = BoostBuild.Tester()
+def test_basic():
+ t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", "import gcc ;")
-t.write("jamfile.jam", "lib a : a.cpp : <include>. ;")
-t.write("a.cpp", """
+ t.write("jamroot.jam", "lib a : a.cpp : <include>. ;")
+ t.write("a.cpp", """\
 #include <a.h>
 void
 # ifdef _WIN32
 __declspec(dllexport)
-# endif
+# endif
 foo() {}
 """)
-t.write("a.h", "//empty file\n")
-
-t.write("d/jamfile.jam", "exe b : b.cpp ..//a ; ")
-t.write("d/b.cpp", """
+ t.write("a.h", "//empty file\n")
+ t.write("d/jamfile.jam", "exe b : b.cpp ..//a ;")
+ t.write("d/b.cpp", """\
 void foo();
 int main() { foo(); }
 """)
+ t.run_build_system(subdir="d")
 
-t.run_build_system(subdir="d")
+ # Path features with condition.
+ t.write("jamroot.jam", "lib a : a.cpp : <variant>debug:<include>. ;")
+ t.rm("bin")
+ t.run_build_system(subdir="d")
 
-# Now test the path features with condition work as well.
-t.write("jamfile.jam", "lib a : a.cpp : <variant>debug:<include>. ;")
-t.rm("bin")
-t.run_build_system(subdir="d")
 
-# Test path features with condition in usage requirements.
-t.write("jamfile.jam", """
+ # Path features with condition in usage requirements.
+ t.write("jamroot.jam", """\
 lib a : a.cpp : <include>. : : <variant>debug:<include>. ;
 """)
-t.write("d/b.cpp", """
+ t.write("d/b.cpp", """\
 #include <a.h>
 void foo();
 int main() { foo(); }
 """)
-t.rm("d/bin")
-t.run_build_system(subdir="d")
+ t.rm("d/bin")
+ t.run_build_system(subdir="d")
+
+ t.cleanup()
+
+
+def test_absolute_paths():
+ """
+ Test that absolute paths inside requirements are ok. The problems
+ appeared only when building targets in subprojects.
 
-# Test that absolute paths inside requirements are ok. The problems appeared
-# only when building targets in subprojects.
-t.write("jamroot.jam", "")
-t.write("jamfile.jam", "build-project x ; ")
-t.write("x/jamfile.jam", """
+ """
+ t = BoostBuild.Tester(use_test_config=False)
+
+ t.write("jamroot.jam", "build-project x ;")
+ t.write("x/jamfile.jam", """\
 local pwd = [ PWD ] ;
 project : requirements <include>$(pwd)/x/include ;
 exe m : m.cpp : <include>$(pwd)/x/include2 ;
 """)
-t.write("x/m.cpp", """
+ t.write("x/m.cpp", """\
 #include <h1.hpp>
 #include <h2.hpp>
 int main() {}
 """)
-t.write("x/include/h1.hpp", "\n")
-t.write("x/include2/h2.hpp", "\n")
+ t.write("x/include/h1.hpp", "\n")
+ t.write("x/include2/h2.hpp", "\n")
 
-t.run_build_system()
-t.expect_addition("x/bin/$toolset/debug/m.exe")
+ t.run_build_system()
+ t.expect_addition("x/bin/$toolset/debug/m.exe")
 
-# Test that "&&" in path features is handled correctly.
-t.rm("bin")
-t.write("jamfile.jam", "build-project sub ;")
-t.write("sub/jamfile.jam", """
-exe a : a.cpp : <include>../h1&&../h2 ;
-""")
-t.write("sub/a.cpp", """
+ t.cleanup()
+
+
+def test_ordered_paths():
+ """Test that "&&" in path features is handled correctly."""
+
+ t = BoostBuild.Tester(use_test_config=False)
+
+ t.write("jamroot.jam", "build-project sub ;")
+ t.write("sub/jamfile.jam", "exe a : a.cpp : <include>../h1&&../h2 ;")
+ t.write("sub/a.cpp", """\
 #include <header.h>
 int main() { return OK; }
 """)
-t.write("h2/header.h", """
-const int OK = 0;
+ t.write("h2/header.h", "int const OK = 0;\n")
+ t.run_build_system()
+ t.expect_addition("sub/bin/$toolset/debug/a.exe")
+
+ t.cleanup()
+
+
+def test_paths_set_by_indirect_conditionals():
+ t = BoostBuild.Tester(pass_d0=False, use_test_config=False)
+
+ header = "child_dir/folder_to_include/some_header.h"
+
+ t.write("jamroot.jam", "build-project child_dir ;")
+ t.write("child_dir/jamfile.jam", """\
+import remote/remote ;
+
+# If we set the <include>folder_to_include property directly, it will work
+obj x1 : x.cpp : <conditional>@attach-include-local ;
+obj x2 : x.cpp : <conditional>@remote/remote.attach-include-remote ;
+
+rule attach-include-local ( properties * )
+{
+ return <include>folder_to_include ;
+}
+""")
+ t.write("child_dir/remote/remote.jam", """\
+rule attach-include-remote ( properties * )
+{
+ return <include>folder_to_include ;
+}
+""")
+ t.write("child_dir/x.cpp", """\
+#include <some_header.h>
+int main() {}
 """)
-t.run_build_system()
-t.expect_addition("sub/bin/$toolset/debug/a.exe")
+ t.write(header, "int some_func();\n")
+ t.write("child_dir/folder_to_include/jamfile.jam", "")
+
+ expected_x1 = "child_dir/bin/$toolset/debug/x1.obj"
+ expected_x2 = "child_dir/bin/$toolset/debug/x2.obj"
+
+ t.run_build_system()
+ t.expect_addition(expected_x1)
+ t.expect_addition(expected_x2)
+
+ t.touch(header)
+ t.run_build_system(subdir="child_dir")
+ t.expect_touch(expected_x1)
+ t.expect_touch(expected_x2)
+
+ t.touch(header)
+ t.run_build_system(["..", "-d2"], subdir="child_dir/folder_to_include")
+ t.expect_touch(expected_x1)
+ t.expect_touch(expected_x2)
+
+ t.cleanup()
+
 
-t.cleanup()
+test_basic()
+test_absolute_paths()
+test_ordered_paths()
+test_paths_set_by_indirect_conditionals()
\ No newline at end of file

Modified: branches/release/tools/build/v2/test/prebuilt.py
==============================================================================
--- branches/release/tools/build/v2/test/prebuilt.py (original)
+++ branches/release/tools/build/v2/test/prebuilt.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,14 +1,14 @@
 #!/usr/bin/python
 
-# Copyright 2002, 2003, 2004 Vladimir Prus
-# 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)
+# Copyright 2002, 2003, 2004 Vladimir Prus
+# 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)
 
 # Test that we can use already built sources
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(["debug", "release"], use_test_config=False)
 
 t.set_tree('prebuilt')
 
@@ -16,17 +16,17 @@
 t.expand_toolset("jamroot.jam")
 
 # First, build the external project.
-t.run_build_system("debug release", subdir="ext")
+t.run_build_system(subdir="ext")
 
-# Then pretend that we do not have the sources for the external project, and can
-# only use compiled binaries.
+# Then pretend that we do not have the sources for the external project, and
+# can only use compiled binaries.
 t.copy("ext/jamfile2.jam", "ext/jamfile.jam")
 t.expand_toolset("ext/jamfile.jam")
 
 # Now check that we can build the main project, and that correct prebuilt file
 # is picked, depending of variant. This also checks that correct includes for
 # prebuilt libraries are used.
-t.run_build_system("debug release")
+t.run_build_system()
 t.expect_addition("bin/$toolset/debug/hello.exe")
 t.expect_addition("bin/$toolset/release/hello.exe")
 
@@ -36,7 +36,7 @@
 # Now test that prebuilt file specified by absolute name works too.
 t.copy("ext/jamfile3.jam", "ext/jamfile.jam")
 t.expand_toolset("ext/jamfile.jam")
-t.run_build_system("debug release")
+t.run_build_system()
 t.expect_addition("bin/$toolset/debug/hello.exe")
 t.expect_addition("bin/$toolset/release/hello.exe")
 

Modified: branches/release/tools/build/v2/test/project_dependencies.py
==============================================================================
--- branches/release/tools/build/v2/test/project_dependencies.py (original)
+++ branches/release/tools/build/v2/test/project_dependencies.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -13,7 +13,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", "build-project src ;")
 

Modified: branches/release/tools/build/v2/test/project_glob.py
==============================================================================
--- branches/release/tools/build/v2/test/project_glob.py (original)
+++ branches/release/tools/build/v2/test/project_glob.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,161 +1,212 @@
 #!/usr/bin/python
 
-# Copyright (C) Vladimir Prus 2003.
+# Copyright (C) 2003. Vladimir Prus
 # 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 accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Test the 'glob' rule in Jamfile context.
 
 import BoostBuild
 
-# Create a temporary working directory.
-t = BoostBuild.Tester()
 
-t.write("jamroot.jam", """
-""")
-
-t.write("d1/a.cpp", """
-int main() {}
-""")
+def test_basic():
+ t = BoostBuild.Tester(use_test_config=False)
 
-t.write("d1/jamfile.jam", """
-exe a : [ glob *.cpp ] ../d2/d//l ;
-""")
-
-t.write("d2/d/l.cpp", """
+ t.write("jamroot.jam", "")
+ t.write("d1/a.cpp", "int main() {}\n")
+ t.write("d1/jamfile.jam", "exe a : [ glob *.cpp ] ../d2/d//l ;")
+ t.write("d2/d/l.cpp", """\
 #if defined(_WIN32)
 __declspec(dllexport)
 void force_import_lib_creation() {}
 #endif
 """)
+ t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;")
+ t.write("d3/d/jamfile.jam", "exe a : [ glob ../*.cpp ] ;")
+ t.write("d3/a.cpp", "int main() {}\n")
 
-t.write("d2/d/jamfile.jam", """
-lib l : [ glob *.cpp ] ;
-""")
+ t.run_build_system(subdir="d1")
+ t.expect_addition("d1/bin/$toolset/debug/a.exe")
 
-t.write("d3/d/jamfile.jam", """
-exe a : [ glob ../*.cpp ] ;
-""")
-
-t.write("d3/a.cpp", """
-int main() {}
-""")
+ t.run_build_system(subdir="d3/d")
+ t.expect_addition("d3/d/bin/$toolset/debug/a.exe")
 
-t.run_build_system(subdir="d1")
-t.expect_addition("d1/bin/$toolset/debug/a.exe")
+ t.rm("d2/d/bin")
+ t.run_build_system(subdir="d2/d")
+ t.expect_addition("d2/d/bin/$toolset/debug/l.dll")
 
-t.run_build_system(subdir="d3/d")
-t.expect_addition("d3/d/bin/$toolset/debug/a.exe")
+ t.cleanup()
 
-t.rm("d2/d/bin")
 
-t.run_build_system(subdir="d2/d")
-t.expect_addition("d2/d/bin/$toolset/debug/l.dll")
+def test_source_location():
+ """
+ Test that when 'source-location' is explicitly-specified glob works
+ relative to the source location.
 
+ """
+ t = BoostBuild.Tester(use_test_config=False)
 
-# Test that when 'source-location' is explicitly-specified glob works relatively
-# to the source location.
-t.rm("d1")
-
-t.write("d1/src/a.cpp", """
-int main() {}
-""")
-
-t.write("d1/jamfile.jam", """
+ t.write("jamroot.jam", "")
+ t.write("d1/a.cpp", "very bad non-compilable file\n")
+ t.write("d1/src/a.cpp", "int main() {}\n")
+ t.write("d1/jamfile.jam", """\
 project : source-location src ;
 exe a : [ glob *.cpp ] ../d2/d//l ;
 """)
+ t.write("d2/d/l.cpp", """\
+#if defined(_WIN32)
+__declspec(dllexport)
+void force_import_lib_creation() {}
+#endif
+""")
+ t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;")
 
-t.run_build_system(subdir="d1")
-t.expect_addition("d1/bin/$toolset/debug/a.exe")
+ t.run_build_system(subdir="d1")
+ t.expect_addition("d1/bin/$toolset/debug/a.exe")
 
-# Test that wildcards can include directories. Also test exclusion patterns.
-t.rm("d1")
+ t.cleanup()
 
-t.write("d1/src/foo/a.cpp", """
-void bar();
-int main() { bar(); }
-""")
 
-t.write("d1/src/bar/b.cpp", """
-void bar() {}
-""")
+def test_wildcards_and_exclusion_patterns():
+ """
+ Test that wildcards can include directories. Also test exclusion
+ patterns.
 
-t.write("d1/src/bar/bad.cpp", """
-very bad non-compilable file
-""")
+ """
+ t = BoostBuild.Tester(use_test_config=False)
 
-t.write("d1/jamfile.jam", """
+ t.write("jamroot.jam", "")
+ t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n")
+ t.write("d1/src/bar/b.cpp", "void bar() {}\n")
+ t.write("d1/src/bar/bad.cpp", "very bad non-compilable file\n")
+ t.write("d1/jamfile.jam", """\
 project : source-location src ;
 exe a : [ glob foo/*.cpp bar/*.cpp : bar/bad* ] ../d2/d//l ;
 """)
+ t.write("d2/d/l.cpp", """\
+#if defined(_WIN32)
+__declspec(dllexport)
+void force_import_lib_creation() {}
+#endif
+""")
+ t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;")
 
-t.run_build_system(subdir="d1")
-t.expect_addition("d1/bin/$toolset/debug/a.exe")
+ t.run_build_system(subdir="d1")
+ t.expect_addition("d1/bin/$toolset/debug/a.exe")
 
+ t.cleanup()
 
-# Test that 'glob-tree' works.
-t.rm("d1/bin/$toolset/debug/a.exe")
 
-t.write("d1/jamfile.jam", """
+def test_glob_tree():
+ """Test that 'glob-tree' works."""
+
+ t = BoostBuild.Tester(use_test_config=False)
+
+ t.write("jamroot.jam", "")
+ t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n")
+ t.write("d1/src/bar/b.cpp", "void bar() {}\n")
+ t.write("d1/src/bar/bad.cpp", "very bad non-compilable file\n")
+ t.write("d1/jamfile.jam", """\
 project : source-location src ;
 exe a : [ glob-tree *.cpp : bad* ] ../d2/d//l ;
 """)
+ t.write("d2/d/l.cpp", """\
+#if defined(_WIN32)
+__declspec(dllexport)
+void force_import_lib_creation() {}
+#endif
+""")
+ t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;")
 
-t.run_build_system(subdir="d1")
-t.expect_addition("d1/bin/$toolset/debug/a.exe")
+ t.run_build_system(subdir="d1")
+ t.expect_addition("d1/bin/$toolset/debug/a.exe")
 
+ t.cleanup()
 
-# Test that directory names in patterns for 'glob-tree' are rejected.
-t.write("d1/jamfile.jam", """
+
+def test_directory_names_in_glob_tree():
+ """Test that directory names in patterns for 'glob-tree' are rejected."""
+
+ t = BoostBuild.Tester(use_test_config=False)
+
+ t.write("jamroot.jam", "")
+ t.write("d1/src/a.cpp", "very bad non-compilable file\n")
+ t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n")
+ t.write("d1/src/bar/b.cpp", "void bar() {}\n")
+ t.write("d1/src/bar/bad.cpp", "very bad non-compilable file\n")
+ t.write("d1/jamfile.jam", """\
 project : source-location src ;
 exe a : [ glob-tree foo/*.cpp bar/*.cpp : bad* ] ../d2/d//l ;
 """)
+ t.write("d2/d/l.cpp", """\
+#if defined(_WIN32)
+__declspec(dllexport)
+void force_import_lib_creation() {}
+#endif
+""")
+ t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;")
 
-t.run_build_system(subdir="d1", status=1)
-t.expect_output_line("error: The patterns * may not include directory")
+ t.run_build_system(subdir="d1", status=1)
+ t.expect_output_lines("error: The patterns * may not include directory")
 
+ t.cleanup()
 
-t.rm("d1/src/bar/bad.cpp")
 
-# Test that 'glob' works with absolute names.
-t.rm("d1/bin")
+def test_glob_with_absolute_names():
+ """Test that 'glob' works with absolute names."""
 
-# Note that to get current dir, we use bjam's PWD, not Python's os.getcwd(),
-# because the former will always return long path while the latter might return
-# a short path, and that will confuse path.glob.
-t.write("d1/jamfile.jam", """
+ t = BoostBuild.Tester(use_test_config=False)
+
+ t.write("jamroot.jam", "")
+ t.write("d1/src/a.cpp", "very bad non-compilable file\n")
+ t.write("d1/src/foo/a.cpp", "void bar(); int main() { bar(); }\n")
+ t.write("d1/src/bar/b.cpp", "void bar() {}\n")
+ # Note that to get the current dir, we use bjam's PWD, not Python's
+ # os.getcwd(), because the former will always return a long path while the
+ # latter might return a short path, which would confuse path.glob.
+ t.write("d1/jamfile.jam", """\
 project : source-location src ;
-local pwd = [ PWD ] ; # Always absolute
+local pwd = [ PWD ] ; # Always absolute.
 exe a : [ glob $(pwd)/src/foo/*.cpp $(pwd)/src/bar/*.cpp ] ../d2/d//l ;
 """)
+ t.write("d2/d/l.cpp", """\
+#if defined(_WIN32)
+__declspec(dllexport)
+void force_import_lib_creation() {}
+#endif
+""")
+ t.write("d2/d/jamfile.jam", "lib l : [ glob *.cpp ] ;")
 
-t.run_build_system(subdir="d1")
-t.expect_addition("d1/bin/$toolset/debug/a.exe")
+ t.run_build_system(subdir="d1")
+ t.expect_addition("d1/bin/$toolset/debug/a.exe")
 
+ t.cleanup()
 
-# Regression test: glob excludes used to be broken when building from a
-# subdirectory.
-t.rm(".")
 
-t.write("jamroot.jam", """
-build-project p ;
-""")
+def test_glob_excludes_in_subdirectory():
+ """
+ Regression test: glob excludes used to be broken when building from a
+ subdirectory.
 
-t.write("p/p.c", """
-int main() {}
-""")
+ """
+ t = BoostBuild.Tester(use_test_config=False)
 
-t.write("p/p_x.c", """
-int main() {}
-""")
+ t.write("jamroot.jam", "build-project p ;")
+ t.write("p/p.c", "int main() {}\n")
+ t.write("p/p_x.c", "very bad non-compilable file\n")
+ t.write("p/jamfile.jam", "exe p : [ glob *.c : p_x.c ] ;")
 
-t.write("p/jamfile.jam", """
-exe p : [ glob *.c : p_x.c ] ;
-""")
+ t.run_build_system(subdir="p")
+ t.expect_addition("p/bin/$toolset/debug/p.exe")
+
+ t.cleanup()
 
-t.run_build_system(subdir="p")
-t.expect_addition("p/bin/$toolset/debug/p.exe")
 
-t.cleanup()
+test_basic()
+test_source_location()
+test_wildcards_and_exclusion_patterns()
+test_glob_tree()
+test_directory_names_in_glob_tree()
+test_glob_with_absolute_names()
+test_glob_excludes_in_subdirectory()

Copied: branches/release/tools/build/v2/test/project_id.py (from r79939, /trunk/tools/build/v2/test/project_id.py)
==============================================================================
--- /trunk/tools/build/v2/test/project_id.py (original)
+++ branches/release/tools/build/v2/test/project_id.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,6 +8,7 @@
 # Tests Boost Build's project-id handling.
 
 import BoostBuild
+import sys
 
 
 def test_assigning_project_ids():
@@ -37,7 +38,7 @@
 use-project id1 : a ;
 # We need to load the 'a' Jamfile module manually as the use-project rule will
 # only schedule the load to be done after the current module load finishes.
-a-module = [ project.load "a" ] ;
+a-module = [ project.load a ] ;
 assert-project-id : $(a-module) ;
 use-project id2 : a ;
 assert-project-id : $(a-module) ;
@@ -63,52 +64,48 @@
     t.cleanup()
 
 
-def test_assigning_using_project_ids_in_target_references():
+def test_using_project_ids_in_target_references():
     t = BoostBuild.Tester()
     __write_appender(t, "appender.jam")
     t.write("jamroot.jam", """\
 import type ;
 type.register AAA : _a ;
 type.register BBB : _b ;
-type.register CCC : _c ;
 
 import appender ;
 appender.register aaa-to-bbb : AAA : BBB ;
-appender.register bbb-to-ccc : BBB : CCC ;
 
-use-project id1 : b ;
-use-project /id2 : b ;
+use-project id1 : a ;
+use-project /id2 : a ;
 
-ccc c1 : /id1//target ;
-ccc c2 : /id2//target ;
-ccc c3 : /id3//target ;
-ccc c4 : b//target ;
-ccc c5 : /project-a1//target ;
-ccc c6 : /project-a2//target ;
-ccc c7 : /project-a3//target ;
+bbb b1 : /id1//target ;
+bbb b2 : /id2//target ;
+bbb b3 : /id3//target ;
+bbb b4 : a//target ;
+bbb b5 : /project-a1//target ;
+bbb b6 : /project-a2//target ;
+bbb b7 : /project-a3//target ;
 
-use-project id3 : b ;
+use-project id3 : a ;
 """)
- t.write("b/source._a", "")
- t.write("b/jamfile.jam", """\
+ t.write("a/source._a", "")
+ t.write("a/jamfile.jam", """\
 project project-a1 ;
 project /project-a2 ;
-bbb target : source._a ;
+import alias ;
+alias target : source._a ;
 project /project-a3 ;
 """)
 
     t.run_build_system()
- t.expect_addition("b/bin/$toolset/target._b")
- t.expect_addition("bin/$toolset/c%d._c" % x for x in range(1, 8))
+ t.expect_addition("bin/$toolset/b%d._b" % x for x in range(1, 8))
     t.expect_nothing_more()
 
     t.cleanup()
 
 
-def test_repeated_ids():
+def test_repeated_ids_for_different_projects():
     t = BoostBuild.Tester()
- t.write("jamroot.jam", "project foo ; project foo ;")
- t.run_build_system()
 
     t.write("a/jamfile.jam", "")
     t.write("jamroot.jam", "project foo ; use-project foo : a ;")
@@ -117,10 +114,12 @@
 error: Attempt to redeclare already registered project id '/foo'.
 error: Original project:
 error: Name: Jamfile<*>
+error: Module: Jamfile<*>
 error: Main id: /foo
 error: File: jamroot.jam
 error: Location: .
 error: New project:
+error: Module: Jamfile<*>
 error: File: a*jamfile.jam
 error: Location: a""")
 
@@ -130,10 +129,12 @@
 error: Attempt to redeclare already registered project id '/foo'.
 error: Original project:
 error: Name: Jamfile<*>
+error: Module: Jamfile<*>
 error: Main id: /foo
 error: File: jamroot.jam
 error: Location: .
 error: New project:
+error: Module: Jamfile<*>
 error: File: a*jamfile.jam
 error: Location: a""")
 
@@ -149,48 +150,140 @@
 error: Attempt to redeclare already registered project id '/foo'.
 error: Original project:
 error: Name: Jamfile<*>
+error: Module: Jamfile<*>
 error: Main id: /foo
 error: File: a*jamfile.jam
 error: Location: a
 error: New project:
+error: Module: Jamfile<*>
 error: File: jamroot.jam
 error: Location: .""")
 
     t.cleanup()
 
 
+def test_repeated_ids_for_same_project():
+ t = BoostBuild.Tester()
+
+ t.write("jamroot.jam", "project foo ; project foo ;")
+ t.run_build_system()
+
+ t.write("jamroot.jam", "project foo ; use-project foo : . ;")
+ t.run_build_system()
+
+ t.write("jamroot.jam", "project foo ; use-project foo : ./. ;")
+ t.run_build_system()
+
+ t.write("jamroot.jam", """\
+project foo ;
+use-project foo : . ;
+use-project foo : ./aaa/.. ;
+use-project foo : ./. ;
+""")
+ t.run_build_system()
+
+ # On Windows we have a case-insensitive file system and we can use
+ # backslashes as path separators.
+ # FIXME: Make a similar test pass on Cygwin.
+ if sys.platform in ['win32']:
+ t.write("a/fOo bAr/b/jamfile.jam", "")
+ t.write("jamroot.jam", r"""
+use-project bar : "a/foo bar/b" ;
+use-project bar : "a/foO Bar/b" ;
+use-project bar : "a/foo BAR/b/" ;
+use-project bar : "a\\.\\FOO bar\\b\\" ;
+""")
+ t.run_build_system()
+ t.rm("a")
+
+ t.write("bar/jamfile.jam", "")
+ t.write("jamroot.jam", """\
+use-project bar : bar ;
+use-project bar : bar/ ;
+use-project bar : bar// ;
+use-project bar : bar/// ;
+use-project bar : bar//// ;
+use-project bar : bar/. ;
+use-project bar : bar/./ ;
+use-project bar : bar/////./ ;
+use-project bar : bar/../bar/xxx/.. ;
+use-project bar : bar/..///bar/xxx///////.. ;
+use-project bar : bar/./../bar/xxx/.. ;
+use-project bar : bar/.////../bar/xxx/.. ;
+use-project bar : bar/././../bar/xxx/.. ;
+use-project bar : bar/././//////////../bar/xxx/.. ;
+use-project bar : bar/.///.////../bar/xxx/.. ;
+use-project bar : bar/./././xxx/.. ;
+use-project bar : bar/xxx////.. ;
+use-project bar : bar/xxx/.. ;
+use-project bar : bar///////xxx/.. ;
+""")
+ t.run_build_system()
+ t.rm("bar")
+
+ # On Windows we have a case-insensitive file system and we can use
+ # backslashes as path separators.
+ # FIXME: Make a similar test pass on Cygwin.
+ if sys.platform in ['win32']:
+ t.write("baR/jamfile.jam", "")
+ t.write("jamroot.jam", r"""
+use-project bar : bar ;
+use-project bar : BAR ;
+use-project bar : bAr ;
+use-project bar : bAr/ ;
+use-project bar : bAr\\ ;
+use-project bar : bAr\\\\ ;
+use-project bar : bAr\\\\///// ;
+use-project bar : bAr/. ;
+use-project bar : bAr/./././ ;
+use-project bar : bAr\\.\\.\\.\\ ;
+use-project bar : bAr\\./\\/.\\.\\ ;
+use-project bar : bAr/.\\././ ;
+use-project bar : Bar ;
+use-project bar : BaR ;
+use-project bar : BaR/./../bAr/xxx/.. ;
+use-project bar : BaR/./..\\bAr\\xxx/.. ;
+use-project bar : BaR/xxx/.. ;
+use-project bar : BaR///\\\\\\//xxx/.. ;
+use-project bar : Bar\\xxx/.. ;
+use-project bar : BAR/xXx/.. ;
+use-project bar : BAR/xXx\\\\/\\/\\//\\.. ;
+""")
+ t.run_build_system()
+ t.rm("baR")
+
+ t.cleanup()
+
+
 def test_unresolved_project_references():
     t = BoostBuild.Tester()
 
     __write_appender(t, "appender.jam")
- t.write("b/source._a", "")
- t.write("b/jamfile.jam", "bbb target : source._a ;")
+ t.write("a/source._a", "")
+ t.write("a/jamfile.jam", "import alias ; alias target : source._a ;")
     t.write("jamroot.jam", """\
 import type ;
 type.register AAA : _a ;
 type.register BBB : _b ;
-type.register CCC : _c ;
 
 import appender ;
 appender.register aaa-to-bbb : AAA : BBB ;
-appender.register bbb-to-ccc : BBB : CCC ;
 
-use-project foo : b ;
+use-project foo : a ;
 
-ccc c1 : b//target ;
-ccc c2 : /foo//target ;
-ccc c-invalid : invalid//target ;
-ccc c-root-invalid : /invalid//target ;
-ccc c-missing-root : foo//target ;
-ccc c-invalid-target : /foo//invalid ;
+bbb b1 : a//target ;
+bbb b2 : /foo//target ;
+bbb b-invalid : invalid//target ;
+bbb b-root-invalid : /invalid//target ;
+bbb b-missing-root : foo//target ;
+bbb b-invalid-target : /foo//invalid ;
 """)
 
- t.run_build_system(["c1", "c2"])
- t.expect_addition("b/bin/$toolset/debug/target._b")
- t.expect_addition("bin/$toolset/debug/c%s._c" % x for x in range(1, 3))
+ t.run_build_system(["b1", "b2"])
+ t.expect_addition("bin/$toolset/debug/b%d._b" % x for x in range(1, 3))
     t.expect_nothing_more()
 
- t.run_build_system(["c-invalid"], status=1)
+ t.run_build_system(["b-invalid"], status=1)
     t.expect_output_lines("""\
 error: Unable to find file or target named
 error: 'invalid//target'
@@ -198,7 +291,7 @@
 error: '.'
 error: could not resolve project reference 'invalid'""")
 
- t.run_build_system(["c-root-invalid"], status=1)
+ t.run_build_system(["b-root-invalid"], status=1)
     t.expect_output_lines("""\
 error: Unable to find file or target named
 error: '/invalid//target'
@@ -206,7 +299,7 @@
 error: '.'
 error: could not resolve project reference '/invalid'""")
 
- t.run_build_system(["c-missing-root"], status=1)
+ t.run_build_system(["b-missing-root"], status=1)
     t.expect_output_lines("""\
 error: Unable to find file or target named
 error: 'foo//target'
@@ -215,7 +308,7 @@
 error: could not resolve project reference 'foo' - possibly missing a """
     "leading slash ('/') character.")
 
- t.run_build_system(["c-invalid-target"], status=1)
+ t.run_build_system(["b-invalid-target"], status=1)
     t.expect_output_lines("""\
 error: Unable to find file or target named
 error: '/foo//invalid'
@@ -315,6 +408,7 @@
 
 
 test_assigning_project_ids()
-test_assigning_using_project_ids_in_target_references()
-test_repeated_ids()
+test_using_project_ids_in_target_references()
+test_repeated_ids_for_same_project()
+test_repeated_ids_for_different_projects()
 test_unresolved_project_references()

Modified: branches/release/tools/build/v2/test/project_root_constants.py
==============================================================================
--- branches/release/tools/build/v2/test/project_root_constants.py (original)
+++ branches/release/tools/build/v2/test/project_root_constants.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,32 +1,32 @@
 #!/usr/bin/python
 
-# Copyright 2003, 2004, 2005 Vladimir Prus
-# 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)
+# Copyright 2003, 2004, 2005 Vladimir Prus
+# 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 BoostBuild
-import string
 
 # Create a temporary working directory.
 t = BoostBuild.Tester()
 
 # Create the needed files.
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 constant FOO : foobar gee ;
 ECHO $(FOO) ;
 """)
 
 t.run_build_system()
-t.fail_test(string.find(t.stdout(), "foobar gee") == -1)
+t.expect_output_lines("foobar gee")
 
 # Regression test: when absolute paths were passed to path-constant rule,
 # Boost.Build failed to recognize path as absolute and prepended the current
 # dir.
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 import path ;
 local here = [ path.native [ path.pwd ] ] ;
 path-constant HERE : $(here) ;
-if $(HERE) != $(here)
+if $(HERE) != $(here)
 {
     ECHO "PWD =" $(here) ;
     ECHO "path constant =" $(HERE) ;
@@ -37,7 +37,7 @@
 
 t.run_build_system()
 
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 # This tests that rule 'hello' will be imported to children unlocalized, and
 # will still access variables in this Jamfile.
 x = 10 ;
@@ -45,22 +45,18 @@
 rule hello ( ) { ECHO "Hello $(x)" ; }
 """)
 
-t.write("d/jamfile.jam", """
+t.write("d/jamfile.jam", """\
 ECHO "d: $(FOO)" ;
 constant BAR : bar ;
 """)
 
-t.write("d/d2/jamfile.jam", """
+t.write("d/d2/jamfile.jam", """\
 ECHO "d2: $(FOO)" ;
 ECHO "d2: $(BAR)" ;
 hello ;
 """)
 
 t.run_build_system(subdir="d/d2")
-t.fail_test(t.stdout().find("""d: foo
-d2: foo
-d2: bar
-Hello 10
-""") == -1)
+t.expect_output_lines("d: foo\nd2: foo\nd2: bar\nHello 10")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/project_root_rule.py
==============================================================================
--- branches/release/tools/build/v2/test/project_root_rule.py (original)
+++ branches/release/tools/build/v2/test/project_root_rule.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -11,7 +11,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 
 t.write("jamroot.jam", """

Modified: branches/release/tools/build/v2/test/project_test3.py
==============================================================================
--- branches/release/tools/build/v2/test/project_test3.py (original)
+++ branches/release/tools/build/v2/test/project_test3.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -3,7 +3,8 @@
 # Copyright 2002, 2003 Dave Abrahams
 # Copyright 2002, 2003, 2004, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 import os
@@ -13,17 +14,17 @@
 # First check some startup.
 t.set_tree("project-test3")
 os.remove("jamroot.jam")
-t.run_build_system(status=1, stdout=
-"""error: Could not find parent for project at '.'
-error: Did not find Jamfile.jam or Jamroot.jam in any parent directory.
-""")
+t.run_build_system(status=1)
+
+t.expect_output_lines("error: Could not find parent for project at '.'\n"
+ "error: Did not find Jamfile.jam or Jamroot.jam in any parent directory.")
 
 t.set_tree("project-test3")
 t.run_build_system()
 
 t.expect_addition("bin/$toolset/debug/a.obj")
-t.expect_content("bin/$toolset/debug/a.obj",
-"""$toolset/debug
+t.expect_content("bin/$toolset/debug/a.obj", """\
+$toolset/debug
 a.cpp
 """)
 
@@ -37,44 +38,44 @@
 )
 
 t.expect_addition("lib/bin/$toolset/debug/b.obj")
-t.expect_content("lib/bin/$toolset/debug/b.obj",
-"""$toolset/debug
+t.expect_content("lib/bin/$toolset/debug/b.obj", """\
+$toolset/debug
 lib/b.cpp
 """)
 
 t.expect_addition("lib/bin/$toolset/debug/m.exe")
-t.expect_content("lib/bin/$toolset/debug/m.exe",
-"""$toolset/debug
+t.expect_content("lib/bin/$toolset/debug/m.exe", """\
+$toolset/debug
 lib/bin/$toolset/debug/b.obj lib2/bin/$toolset/debug/c.obj
 """)
 
 t.expect_addition("lib2/bin/$toolset/debug/c.obj")
-t.expect_content("lib2/bin/$toolset/debug/c.obj",
-"""$toolset/debug
+t.expect_content("lib2/bin/$toolset/debug/c.obj", """\
+$toolset/debug
 lib2/c.cpp
 """)
 
 t.expect_addition("lib2/bin/$toolset/debug/d.obj")
-t.expect_content("lib2/bin/$toolset/debug/d.obj",
-"""$toolset/debug
+t.expect_content("lib2/bin/$toolset/debug/d.obj", """\
+$toolset/debug
 lib2/d.cpp
 """)
 
 t.expect_addition("lib2/bin/$toolset/debug/l.exe")
-t.expect_content("lib2/bin/$toolset/debug/l.exe",
-"""$toolset/debug
+t.expect_content("lib2/bin/$toolset/debug/l.exe", """\
+$toolset/debug
 lib2/bin/$toolset/debug/c.obj bin/$toolset/debug/a.obj
 """)
 
 t.expect_addition("lib2/helper/bin/$toolset/debug/e.obj")
-t.expect_content("lib2/helper/bin/$toolset/debug/e.obj",
-"""$toolset/debug
+t.expect_content("lib2/helper/bin/$toolset/debug/e.obj", """\
+$toolset/debug
 lib2/helper/e.cpp
 """)
 
 t.expect_addition("lib3/bin/$toolset/debug/f.obj")
-t.expect_content("lib3/bin/$toolset/debug/f.obj",
-"""$toolset/debug
+t.expect_content("lib3/bin/$toolset/debug/f.obj", """\
+$toolset/debug
 lib3/f.cpp lib2/helper/bin/$toolset/debug/e.obj
 """)
 
@@ -84,13 +85,13 @@
                 "bin/$toolset/debug/a.exe",
                 "lib2/bin/$toolset/debug/l.exe"])
 
-t.run_build_system(extra_args="release optimization=off,speed")
+t.run_build_system(["release", "optimization=off,speed"])
 t.expect_addition(["bin/$toolset/release/a.exe",
                   "bin/$toolset/release/a.obj",
                   "bin/$toolset/release/optimization-off/a.exe",
                   "bin/$toolset/release/optimization-off/a.obj"])
 
-t.run_build_system(extra_args='--clean-all')
+t.run_build_system(["--clean-all"])
 t.expect_removal(["bin/$toolset/debug/a.obj",
                  "bin/$toolset/debug/a.exe",
                  "lib/bin/$toolset/debug/b.obj",
@@ -102,32 +103,34 @@
 
 # Now test target ids in command line.
 t.set_tree("project-test3")
-t.run_build_system("lib//b.obj")
+t.run_build_system(["lib//b.obj"])
 t.expect_addition("lib/bin/$toolset/debug/b.obj")
 t.expect_nothing_more()
 
-t.run_build_system("--clean lib//b.obj")
+t.run_build_system(["--clean", "lib//b.obj"])
 t.expect_removal("lib/bin/$toolset/debug/b.obj")
 t.expect_nothing_more()
 
-t.run_build_system("lib//b.obj")
+t.run_build_system(["lib//b.obj"])
 t.expect_addition("lib/bin/$toolset/debug/b.obj")
 t.expect_nothing_more()
 
-t.run_build_system("release lib2/helper//e.obj /lib3//f.obj")
+t.run_build_system(["release", "lib2/helper//e.obj", "/lib3//f.obj"])
 t.expect_addition("lib2/helper/bin/$toolset/release/e.obj")
 t.expect_addition("lib3/bin/$toolset/release/f.obj")
 t.expect_nothing_more()
 
 # Test project ids in command line work as well.
 t.set_tree("project-test3")
-t.run_build_system("/lib2")
-t.expect_addition("lib2/bin/$toolset/debug/" * BoostBuild.List("c.obj d.obj l.exe"))
+t.run_build_system(["/lib2"])
+t.expect_addition("lib2/bin/$toolset/debug/" *
+ BoostBuild.List("c.obj d.obj l.exe"))
 t.expect_addition("bin/$toolset/debug/a.obj")
 t.expect_nothing_more()
 
-t.run_build_system("lib")
-t.expect_addition("lib/bin/$toolset/debug/" * BoostBuild.List("b.obj m.exe"))
+t.run_build_system(["lib"])
+t.expect_addition("lib/bin/$toolset/debug/" *
+ BoostBuild.List("b.obj m.exe"))
 t.expect_nothing_more()
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/property_expansion.py
==============================================================================
--- branches/release/tools/build/v2/test/property_expansion.py (original)
+++ branches/release/tools/build/v2/test/property_expansion.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,29 +1,28 @@
 #!/usr/bin/python
 
-# Copyright 2003 Vladimir Prus
-# 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)
+# Copyright 2003 Vladimir Prus
+# 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)
 
 # Test that free property inside.
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", """
-project ;
+t.write("jamroot.jam", """\
 variant debug-AA : debug : <define>AA ;
 alias all : hello ;
 exe hello : hello.cpp ;
 explicit hello ;
 """)
 
-t.write("hello.cpp", """
+t.write("hello.cpp", """\
 #ifdef AA
 int main() {}
 #endif
 """)
 
-t.run_build_system("debug-AA")
+t.run_build_system(["debug-AA"])
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/rebuilds.py
==============================================================================
--- branches/release/tools/build/v2/test/rebuilds.py (original)
+++ branches/release/tools/build/v2/test/rebuilds.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,13 +2,29 @@
 
 # Copyright 2005 Dave Abrahams
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
-t = BoostBuild.Tester(pass_toolset=0)
 
-t.write('file.jam', '''
+def wait_for_bar(t):
+ """
+ Wait to make the test system correctly recognize the 'bar' file as
+ touched after the next build run. Without the wait, the next build run may
+ rebuild the 'bar' file with the new and the old file modification timestamp
+ too close to each other - which could, depending on the currently supported
+ file modification timestamp resolution, be detected as 'no change' by the
+ testing system.
+
+ """
+ t.wait_for_time_change("bar", touch=False)
+
+
+t = BoostBuild.Tester(["-ffile.jam", "-d+3", "-d+12", "-d+13"], pass_d0=False,
+ pass_toolset=0)
+
+t.write("file.jam", """\
 rule make
 {
     DEPENDS $(<) : $(>) ;
@@ -25,27 +41,28 @@
 REBUILDS foo : bar ;
 make bar : baz ;
 make aux2 : bar ;
-''')
+""")
 
-t.write('baz', 'nothing\n')
+t.write("baz", "nothing")
 
-t.run_build_system('-ffile.jam bar')
-t.expect_addition('bar')
+t.run_build_system(["bar"])
+t.expect_addition("bar")
 t.expect_nothing_more()
 
-t.wait_for_time_change_since_last_build()
-t.run_build_system('-ffile.jam foo')
-t.expect_touch('bar')
-t.expect_addition('foo')
+wait_for_bar(t)
+t.run_build_system(["foo"])
+t.expect_touch("bar")
+t.expect_addition("foo")
 t.expect_nothing_more()
 
-t.run_build_system('-ffile.jam')
-t.expect_addition(['aux1', 'aux2'])
+t.run_build_system()
+t.expect_addition(["aux1", "aux2"])
 t.expect_nothing_more()
 
-t.touch('bar')
-t.run_build_system('-ffile.jam')
-t.expect_touch(['foo', 'aux1', 'aux2'])
+t.touch("bar")
+wait_for_bar(t)
+t.run_build_system()
+t.expect_touch(["foo", "bar", "aux1", "aux2"])
 t.expect_nothing_more()
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/regression.py
==============================================================================
--- branches/release/tools/build/v2/test/regression.py (original)
+++ branches/release/tools/build/v2/test/regression.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,11 +10,10 @@
 import BoostBuild
 
 # Create a temporary working directory.
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("c.cpp", "\n")
-
-t.write("r.cpp", """
+t.write("r.cpp", """\
 void helper();
 
 #include <iostream>
@@ -25,17 +24,11 @@
        std::cout << av[ i ] << '\\n';
 }
 """)
+t.write("c-f.cpp", "int\n")
+t.write("r-f.cpp", "int main() { return 1; }\n")
 
-t.write("c-f.cpp", """
-int
-""")
-
-t.write("r-f.cpp", """
-int main() { return 1; }
-""")
-
-
-t.write("jamfile.jam", """
+t.write("jamroot.jam", "")
+t.write("jamfile.jam", """\
 import testing ;
 compile c.cpp ;
 compile-fail c-f.cpp ;
@@ -43,11 +36,8 @@
 run-fail r-f.cpp ;
 """)
 
-t.write("libs/jamfile.jam", """
-lib helper : helper.cpp ;
-""")
-
-t.write("libs/helper.cpp", """
+t.write("libs/jamfile.jam", "lib helper : helper.cpp ;")
+t.write("libs/helper.cpp", """\
 void
 #if defined(_WIN32)
 __declspec(dllexport)
@@ -55,10 +45,8 @@
 helper() {}
 """)
 
-t.write("jamroot.jam", "")
-
 # First test that when outcomes are expected, all .test files are created.
-t.run_build_system("hardcode-dll-paths=false", stderr=None, status=None)
+t.run_build_system(["hardcode-dll-paths=false"], stderr=None, status=None)
 t.expect_addition("bin/c.test/$toolset/debug/c.test")
 t.expect_addition("bin/c-f.test/$toolset/debug/c-f.test")
 t.expect_addition("bin/r.test/$toolset/debug/r.test")
@@ -69,7 +57,7 @@
                  "foo\nbar\n*\nEXIT STATUS: 0*\n", True)
 
 # Test that input file is handled as well.
-t.write("r.cpp", """
+t.write("r.cpp", """\
 #include <iostream>
 #include <fstream>
 int main( int ac, char * av[] )
@@ -84,7 +72,7 @@
 
 t.write("dir/input.txt", "test input")
 
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 import testing ;
 compile c.cpp ;
 obj c-obj : c.cpp ;
@@ -95,18 +83,19 @@
 time compilation : c-obj ;
 """)
 
-t.run_build_system('hardcode-dll-paths=false')
-t.expect_content("bin/r.test/$toolset/debug/r.output",
- "test input\nEXIT STATUS: 0\n")
+t.run_build_system(["hardcode-dll-paths=false"])
+t.expect_content("bin/r.test/$toolset/debug/r.output", """\
+test input
+EXIT STATUS: 0
+""")
 
 t.expect_addition('bin/$toolset/debug/execution.time')
 t.expect_addition('bin/$toolset/debug/compilation.time')
 
 # Make sure test failures are detected. Reverse expectation and see if .test
 # files are created or not.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 import testing ;
-
 compile-fail c.cpp ;
 compile c-f.cpp ;
 run-fail r.cpp : : dir/input.txt ;
@@ -115,7 +104,7 @@
 
 t.touch(BoostBuild.List("c.cpp c-f.cpp r.cpp r-f.cpp"))
 
-t.run_build_system("hardcode-dll-paths=false", stderr=None, status=1)
+t.run_build_system(["hardcode-dll-paths=false"], stderr=None, status=1)
 t.expect_removal("bin/c.test/$toolset/debug/c.test")
 t.expect_removal("bin/c-f.test/$toolset/debug/c-f.test")
 t.expect_removal("bin/r.test/$toolset/debug/r.test")

Modified: branches/release/tools/build/v2/test/relative_sources.py
==============================================================================
--- branches/release/tools/build/v2/test/relative_sources.py (original)
+++ branches/release/tools/build/v2/test/relative_sources.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,7 +9,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Test that relative path to source, 'src', is preserved.
 t.write("jamroot.jam", "exe a : src/a.cpp ;")

Modified: branches/release/tools/build/v2/test/remove_requirement.py
==============================================================================
--- branches/release/tools/build/v2/test/remove_requirement.py (original)
+++ branches/release/tools/build/v2/test/remove_requirement.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,7 +7,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 
 t.write("jamroot.jam", """

Copied: branches/release/tools/build/v2/test/rescan_header.py (from r78248, /trunk/tools/build/v2/test/rescan_header.py)
==============================================================================
--- /trunk/tools/build/v2/test/rescan_header.py (original)
+++ branches/release/tools/build/v2/test/rescan_header.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,28 +1,24 @@
 #!/usr/bin/python
 
 # Copyright 2012 Steven Watanabe
-# 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)
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
-import os
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-# Test a header loop that depends on (but does not contain)
-# a generated header.
-t.write("test.cpp", """
-#include "header1.h"
-""")
+# Test a header loop that depends on (but does not contain) a generated header.
+t.write("test.cpp", '#include "header1.h"\n')
 
-t.write("header1.h", """
+t.write("header1.h", """\
 #ifndef HEADER1_H
 #define HEADER1_H
 #include "header2.h"
 #endif
 """)
 
-t.write("header2.h", """
+t.write("header2.h", """\
 #ifndef HEADER2_H
 #define HEADER2_H
 #include "header1.h"
@@ -30,19 +26,15 @@
 #endif
 """)
 
-t.write("header3.in", """
-/* empty file */
-""")
+t.write("header3.in", "/* empty file */\n")
 
-t.write("Jamroot.jam", """
+t.write("jamroot.jam", """\
 import common ;
-
 make header3.h : header3.in : @common.copy ;
 obj test : test.cpp : <implicit-dependency>header3.h ;
-
 """)
 
-t.run_build_system("-j2")
+t.run_build_system(["-j2"])
 t.expect_addition("bin/$toolset/debug/header3.h")
 t.expect_addition("bin/$toolset/debug/test.obj")
 t.expect_nothing_more()
@@ -50,29 +42,69 @@
 t.rm(".")
 
 # Test a linear sequence of generated headers.
-t.write("test.cpp", """
-#include "header1.h"
+t.write("test.cpp", '#include "header1.h"\n')
+
+t.write("header1.in", """\
+#ifndef HEADER1_H
+#define HEADER1_H
+#include "header2.h"
+#endif
 """)
 
-t.write("header1.in", """
+t.write("header2.in", """\
+#ifndef HEADER2_H
+#define HEADER2_H
+#include "header3.h"
+#endif
+""")
+
+t.write("header3.in", "/* empty file */\n")
+
+t.write("jamroot.jam", """\
+import common ;
+make header1.h : header1.in : @common.copy ;
+make header2.h : header2.in : @common.copy ;
+make header3.h : header3.in : @common.copy ;
+obj test : test.cpp :
+ <implicit-dependency>header1.h
+ <implicit-dependency>header2.h
+ <implicit-dependency>header3.h ;
+""")
+
+t.run_build_system(["-j2", "test"])
+t.expect_addition("bin/$toolset/debug/header1.h")
+t.expect_addition("bin/$toolset/debug/header2.h")
+t.expect_addition("bin/$toolset/debug/header3.h")
+t.expect_addition("bin/$toolset/debug/test.obj")
+t.expect_nothing_more()
+
+t.rm(".")
+
+# Test a loop in generated headers.
+t.write("test.cpp", '#include "header1.h"\n')
+
+t.write("header1.in", """\
 #ifndef HEADER1_H
 #define HEADER1_H
 #include "header2.h"
 #endif
 """)
 
-t.write("header2.in", """
+t.write("header2.in", """\
 #ifndef HEADER2_H
 #define HEADER2_H
 #include "header3.h"
 #endif
 """)
 
-t.write("header3.in", """
-/* empty file */
+t.write("header3.in", """\
+#ifndef HEADER2_H
+#define HEADER2_H
+#include "header1.h"
+#endif
 """)
 
-t.write("Jamroot.jam", """
+t.write("jamroot.jam", """\
 import common ;
 
 actions copy {
@@ -82,19 +114,152 @@
 
 make header1.h : header1.in : @common.copy ;
 make header2.h : header2.in : @common.copy ;
-make header3.h : header2.in : @common.copy ;
+make header3.h : header3.in : @common.copy ;
 obj test : test.cpp :
- <implicit-dependency>header1.h
- <implicit-dependency>header2.h
- <implicit-dependency>header3.h
- ;
+ <implicit-dependency>header1.h
+ <implicit-dependency>header2.h
+ <implicit-dependency>header3.h ;
 """)
 
-t.run_build_system("-j2 test")
+t.run_build_system(["-j2", "test"])
 t.expect_addition("bin/$toolset/debug/header1.h")
 t.expect_addition("bin/$toolset/debug/header2.h")
 t.expect_addition("bin/$toolset/debug/header3.h")
 t.expect_addition("bin/$toolset/debug/test.obj")
 t.expect_nothing_more()
 
+t.rm(".")
+
+# Test that all the dependencies of a loop are updated before any of the
+# dependents.
+t.write("test1.cpp", '#include "header1.h"\n')
+
+t.write("test2.cpp", """\
+#include "header2.h"
+int main() {}
+""")
+
+t.write("header1.h", """\
+#ifndef HEADER1_H
+#define HEADER1_H
+#include "header2.h"
+#endif
+""")
+
+t.write("header2.h", """\
+#ifndef HEADER2_H
+#define HEADER2_H
+#include "header1.h"
+#include "header3.h"
+#endif
+""")
+
+t.write("header3.in", "\n")
+
+t.write("sleep.bat", """\
+::@timeout /T %1 /NOBREAK >nul
+@ping 127.0.0.1 -n 2 -w 1000 >nul
+@ping 127.0.0.1 -n %1 -w 1000 >nul
+@exit /B 0
+""")
+
+t.write("jamroot.jam", """\
+import common ;
+import os ;
+
+if [ os.name ] = NT
+{
+ SLEEP = call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
+
+rule copy { common.copy $(<) : $(>) ; }
+actions copy { $(SLEEP) 1 }
+
+make header3.h : header3.in : @copy ;
+exe test : test2.cpp test1.cpp : <implicit-dependency>header3.h ;
+""")
+
+t.run_build_system(["-j2", "test"])
+t.expect_addition("bin/$toolset/debug/header3.h")
+t.expect_addition("bin/$toolset/debug/test1.obj")
+t.expect_addition("bin/$toolset/debug/test2.obj")
+t.expect_addition("bin/$toolset/debug/test.exe")
+t.expect_nothing_more()
+
+t.touch("header3.in")
+t.run_build_system(["-j2", "test"])
+t.expect_touch("bin/$toolset/debug/header3.h")
+t.expect_touch("bin/$toolset/debug/test1.obj")
+t.expect_touch("bin/$toolset/debug/test2.obj")
+t.expect_touch("bin/$toolset/debug/test.exe")
+t.expect_nothing_more()
+
+t.rm(".")
+
+# Test a loop that includes a generated header
+t.write("test1.cpp", '#include "header1.h"\n')
+t.write("test2.cpp", """\
+#include "header2.h"
+int main() {}
+""")
+
+t.write("header1.h", """\
+#ifndef HEADER1_H
+#define HEADER1_H
+#include "header2.h"
+#endif
+""")
+
+t.write("header2.in", """\
+#ifndef HEADER2_H
+#define HEADER2_H
+#include "header3.h"
+#endif
+""")
+
+t.write("header3.h", """\
+#ifndef HEADER3_H
+#define HEADER3_H
+#include "header1.h"
+#endif
+""")
+
+t.write("sleep.bat", """\
+::@timeout /T %1 /NOBREAK >nul
+@ping 127.0.0.1 -n 2 -w 1000 >nul
+@ping 127.0.0.1 -n %1 -w 1000 >nul
+@exit /B 0
+""")
+
+t.write("jamroot.jam", """\
+import common ;
+import os ;
+
+if [ os.name ] = NT
+{
+ SLEEP = call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
+
+rule copy { common.copy $(<) : $(>) ; }
+actions copy { $(SLEEP) 1 }
+
+make header2.h : header2.in : @copy ;
+exe test : test2.cpp test1.cpp : <implicit-dependency>header2.h <include>. ;
+""")
+
+t.run_build_system(["-j2", "test"])
+t.expect_addition("bin/$toolset/debug/header2.h")
+t.expect_addition("bin/$toolset/debug/test1.obj")
+t.expect_addition("bin/$toolset/debug/test2.obj")
+t.expect_addition("bin/$toolset/debug/test.exe")
+t.expect_nothing_more()
+
 t.cleanup()

Modified: branches/release/tools/build/v2/test/resolution.py
==============================================================================
--- branches/release/tools/build/v2/test/resolution.py (original)
+++ branches/release/tools/build/v2/test/resolution.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,8 +1,8 @@
 #!/usr/bin/python
 
 # Copyright (C) Vladimir Prus 2006.
-# Distributed under the Boost Software License, Version 1.0. (See
-# accompanying file LICENSE_1_0.txt or copy at
+# 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)
 
 # Tests for the target id resolution process.
@@ -10,28 +10,26 @@
 import BoostBuild
 
 # Create a temporary working directory.
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Create the needed files
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 exe hello : hello.cpp ;
 # This should use the 'hello' target, even if there is a 'hello' file in the
 # current dir.
 install s : hello : <location>. ;
 """)
 
-t.write("hello.cpp", """
-int main() {}
-""")
+t.write("hello.cpp", "int main() {}\n")
 
 t.run_build_system()
 
 t.expect_addition("bin/$toolset/debug/hello.obj")
 
 t.touch("hello.cpp")
-t.run_build_system("s")
-# If 'hello' in the 's' target resolved to file in the current dir, nothing will
-# be rebuilt.
+t.run_build_system(["s"])
+# If 'hello' in the 's' target resolved to file in the current dir, nothing
+# will be rebuilt.
 t.expect_touch("bin/$toolset/debug/hello.obj")
 
 t.cleanup()

Copied: branches/release/tools/build/v2/test/scanner_causing_rebuilds.py (from r79599, /trunk/tools/build/v2/test/scanner_causing_rebuilds.py)
==============================================================================
--- /trunk/tools/build/v2/test/scanner_causing_rebuilds.py (original)
+++ branches/release/tools/build/v2/test/scanner_causing_rebuilds.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -18,7 +18,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("foo.jam", r"""
 import common ;

Modified: branches/release/tools/build/v2/test/searched_lib.py
==============================================================================
--- branches/release/tools/build/v2/test/searched_lib.py (original)
+++ branches/release/tools/build/v2/test/searched_lib.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,13 +12,13 @@
 import os
 import string
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 
 # To start with, we have to prepare a library to link with.
 t.write("lib/jamroot.jam", "")
 t.write("lib/jamfile.jam", "lib test_lib : test_lib.cpp ;")
-t.write("lib/test_lib.cpp", """
+t.write("lib/test_lib.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
@@ -42,21 +42,20 @@
 # Test that the simplest usage of searched library works.
 t.write("jamroot.jam", "")
 
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 import path ;
 import project ;
-
 exe main : main.cpp helper ;
 lib helper : helper.cpp test_lib ;
 lib test_lib : : <name>test_lib <search>lib ;
 """)
 
-t.write("main.cpp", """
+t.write("main.cpp", """\
 void helper();
 int main() { helper(); }
 """)
 
-t.write("helper.cpp", """
+t.write("helper.cpp", """\
 void foo();
 void
 #if defined(_WIN32)
@@ -65,14 +64,13 @@
 helper() { foo(); }
 """)
 
-t.run_build_system("-d2")
+t.run_build_system(["-d2"])
 t.expect_addition("bin/$toolset/debug/main.exe")
 t.rm("bin/$toolset/debug/main.exe")
 
 
 # Test that 'unit-test' will correctly add runtime paths to searched libraries.
-t.write("jamfile.jam", """
-
+t.write("jamfile.jam", """\
 import path ;
 import project ;
 import testing ;
@@ -91,7 +89,7 @@
 
 # Now try using searched lib from static lib. Request shared version of searched
 # lib, since we do not have a static one handy.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe main : main.cpp helper ;
 lib helper : helper.cpp test_lib/<link>shared : <link>static ;
 lib test_lib : : <name>test_lib <search>lib ;
@@ -109,17 +107,17 @@
 # works nicely in some cases, sending output from compiler to file 'z'. This
 # problem shows up when searched libs are in usage requirements.
 t.write("jamfile.jam", "exe main : main.cpp d/d2//a ;")
-t.write("main.cpp", """
+t.write("main.cpp", """\
 void foo();
 int main() { foo(); }
 """)
 
-t.write("d/d2/jamfile.jam", """
+t.write("d/d2/jamfile.jam", """\
 lib test_lib : : <name>test_lib <search>../../lib ;
 lib a : a.cpp : : : <library>test_lib ;
 """)
 
-t.write("d/d2/a.cpp", """
+t.write("d/d2/a.cpp", """\
 #ifdef _WIN32
 __declspec(dllexport) int force_library_creation_for_a;
 #endif
@@ -138,13 +136,13 @@
 
 # The 'l' library will be built in two variants: 'debug' (directly requested)
 # and 'release' (requested from 'a').
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp l/<variant>release ;
 lib l : : <name>l_d <variant>debug ;
 lib l : : <name>l_r <variant>release ;
 """)
 
-t.run_build_system("-n")
+t.run_build_system(["-n"])
 
 
 # A regression test. Two virtual target with the same properties were created
@@ -152,35 +150,33 @@
 # targets. The final error is correct, but we should not create two duplicated
 # targets. Thanks to Andre Hentz for finding this bug.
 t.write("jamroot.jam", "")
-
 t.write("a.cpp", "")
-
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 project a : requirements <runtime-link>static ;
 static-lib a : a.cpp l ;
 lib l : : <name>l_f ;
 """)
 
-t.run_build_system("-n")
+t.run_build_system(["-n"])
 
 
 # Make sure plain "lib foobar ; " works.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp foobar ;
 lib foobar ;
 """)
 
-t.run_build_system("-n -d2")
+t.run_build_system(["-n", "-d2"])
 t.fail_test(string.find(t.stdout(), "foobar") == -1)
 
 
 # Make sure plain "lib foo bar ; " works.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 exe a : a.cpp foo bar ;
 lib foo bar ;
 """)
 
-t.run_build_system("-n -d2")
+t.run_build_system(["-n", "-d2"])
 t.fail_test(string.find(t.stdout(), "foo") == -1)
 t.fail_test(string.find(t.stdout(), "bar") == -1)
 

Modified: branches/release/tools/build/v2/test/skipping.py
==============================================================================
--- branches/release/tools/build/v2/test/skipping.py (original)
+++ branches/release/tools/build/v2/test/skipping.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,21 +9,12 @@
 import BoostBuild
 
 # Create a temporary working directory.
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("a.cpp", """
-int main() {}
-""")
-
-t.write("b.cpp", """
-int main() {}
-""")
-
-t.write("c.cpp", """
-int main() {}
-""")
-
-t.write("jamroot.jam", """
+t.write("a.cpp", "int main() {}\n")
+t.write("b.cpp", "int main() {}\n")
+t.write("c.cpp", "int main() {}\n")
+t.write("jamroot.jam", """\
 import feature ;
 feature.feature foo : 1 2 : link-incompatible ;
 exe a : a.cpp : <foo>1 ;
@@ -31,6 +22,6 @@
 exe c : c.cpp ;
 """)
 
-t.run_build_system("foo=1")
+t.run_build_system(["foo=1"])
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/sort_rule.py
==============================================================================
--- branches/release/tools/build/v2/test/sort_rule.py (original)
+++ branches/release/tools/build/v2/test/sort_rule.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,29 +1,28 @@
 #!/usr/bin/python
 
-# Copyright (C) Jurko Gospodnetic 2008.
-# 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)
+# Copyright (C) 2008. Jurko Gospodnetic
+# 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)
 
 # Tests for the Boost Jam builtin SORT rule.
 
 import BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # testSORTCorrectness()
 # ---------------------
 #
-################################################################################
+###############################################################################
 
 def testSORTCorrectness():
- """Testing that Boost Jam's SORT builtin rule actually sorts correctly.
- """
- t = BoostBuild.Tester("-f test.jam -d1", pass_toolset=False,
+ """Testing that Boost Jam's SORT builtin rule actually sorts correctly."""
+ t = BoostBuild.Tester(["-ftest.jam", "-d1"], pass_toolset=False,
         use_test_config=False)
 
- t.write("test.jam", """
+ t.write("test.jam", """\
 NOCARE all ;
 source-data = 1 8 9 2 7 3 4 7 1 27 27 9 98 98 1 1 4 5 6 2 3 4 8 1 -2 -2 0 0 0 ;
 target-data = -2 -2 0 0 0 1 1 1 1 1 2 2 27 27 3 3 4 4 4 5 6 7 7 8 8 9 9 98 98 ;
@@ -40,31 +39,33 @@
 """)
 
     t.run_build_system()
- t.expect_output_line("starting up")
- t.expect_output_line("done")
- t.expect_output_line("SORT error", False)
+ t.expect_output_lines("starting up")
+ t.expect_output_lines("done")
+ t.expect_output_lines("SORT error", False)
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # testSORTDuration()
 # ------------------
 #
-################################################################################
+###############################################################################
 
 def testSORTDuration():
- """Regression test making sure Boost Jam's SORT builtin rule does not get
+ """
+ Regression test making sure Boost Jam's SORT builtin rule does not get
     quadratic behaviour again in this use case.
+
     """
- t = BoostBuild.Tester("-f test.jam -d1", pass_toolset=False,
+ t = BoostBuild.Tester(["-ftest.jam", "-d1"], pass_toolset=False,
         use_test_config=False)
 
     f = open(t.workpath("test.jam"), "w")
     print >> f, "data = "
     for i in range(0, 20000):
- if i % 2 != 0:
+ if i % 2:
             print >> f, '"aaa"'
         else:
             print >> f, '"bbb"'
@@ -78,18 +79,18 @@
     f.close()
 
     t.run_build_system(expected_duration=1)
- t.expect_output_line("starting up")
- t.expect_output_line("done")
+ t.expect_output_lines("starting up")
+ t.expect_output_lines("done")
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
 testSORTCorrectness()
 testSORTDuration()

Modified: branches/release/tools/build/v2/test/source_locations.py
==============================================================================
--- branches/release/tools/build/v2/test/source_locations.py (original)
+++ branches/release/tools/build/v2/test/source_locations.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,7 +9,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", """
 path-constant SRC1 : "./src1" ;

Copied: branches/release/tools/build/v2/test/space_in_path.py (from r78538, /trunk/tools/build/v2/test/space_in_path.py)
==============================================================================
--- /trunk/tools/build/v2/test/space_in_path.py (original)
+++ branches/release/tools/build/v2/test/space_in_path.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,23 +8,14 @@
 
 import BoostBuild
 
-class unsplit(object):
- def __init__(self, value):
- self.value = value
- def split(self, ignored):
- return self.value
+t = BoostBuild.Tester(use_test_config=False)
 
-t = BoostBuild.Tester()
-
-t.write("has space/Jamroot.jam", """
+t.write("has space/jamroot.jam", """\
 import testing ;
 unit-test test : test.cpp ;
 """)
+t.write("has space/test.cpp", "int main() {}\n")
 
-t.write("has space/test.cpp", """
-int main() {}
-""")
-
-t.run_build_system(unsplit(["has space"]))
+t.run_build_system(["has space"])
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/stage.py
==============================================================================
--- branches/release/tools/build/v2/test/stage.py (original)
+++ branches/release/tools/build/v2/test/stage.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -9,25 +9,20 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("jamroot.jam", "import gcc ;")
-
-t.write("jamfile.jam", """
+t.write("jamroot.jam", "")
+t.write("jamfile.jam", """\
 lib a : a.cpp ;
 stage dist : a a.h auxilliary/1 ;
 """)
-
-t.write(
- "a.cpp",
-"""
+t.write("a.cpp", """\
 int
 #ifdef _WIN32
 __declspec(dllexport)
 #endif
 must_export_something;
 """)
-
 t.write("a.h", "")
 t.write("auxilliary/1", "")
 
@@ -35,8 +30,8 @@
 t.expect_addition(["dist/a.dll", "dist/a.h", "dist/1"])
 
 
-# Regression test: the following was causing the "duplicate target name" error.
-t.write("jamfile.jam", """
+# Regression test: the following was causing a "duplicate target name" error.
+t.write("jamfile.jam", """\
 project : requirements <hardcode-dll-paths>true ;
 lib a : a.cpp ;
 stage dist : a a.h auxilliary/1 ;
@@ -47,7 +42,7 @@
 
 
 # Test the <location> property.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 lib a : a.cpp ;
 stage dist : a : <variant>debug:<location>ds <variant>release:<location>rs ;
 """)
@@ -55,24 +50,19 @@
 t.run_build_system()
 t.expect_addition("ds/a.dll")
 
-t.run_build_system("release")
+t.run_build_system(["release"])
 t.expect_addition("rs/a.dll")
 
 
 # Test the <location> property in subprojects. Thanks to Kirill Lapshin for the
 # bug report.
 
-t.write("jamroot.jam", """
-path-constant DIST : dist ;
-""")
-
+t.write("jamroot.jam", "path-constant DIST : dist ;")
 t.write("jamfile.jam", "build-project d ;")
-
-t.write("d/jamfile.jam", """
+t.write("d/jamfile.jam", """\
 exe a : a.cpp ;
 stage dist : a : <location>$(DIST) ;
 """)
-
 t.write("d/a.cpp", "int main() {}\n")
 
 t.run_build_system()
@@ -89,19 +79,16 @@
 
 
 # Check that 'stage' does not incorrectly reset target suffixes.
-t.write("a.cpp", """
-int main() {}
-""")
-
-t.write("jamroot.jam", """
+t.write("a.cpp", "int main() {}\n")
+t.write("jamroot.jam", """\
 import type ;
 type.register MYEXE : : EXE ;
 type.set-generated-target-suffix MYEXE : <optimization>off : myexe ;
 """)
 
-# Since <optimization>off is in properties when 'a' is built, and staged, its
+# Since <optimization>off is in properties when 'a' is built and staged, its
 # suffix should be "myexe".
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 stage dist : a ;
 myexe a : a.cpp ;
 """)
@@ -110,26 +97,20 @@
 t.expect_addition("dist/a.myexe")
 
 # Test 'stage's ability to traverse dependencies.
-t.write("a.cpp", """
-int main() {}
-""")
-
-t.write("l.cpp", """
+t.write("a.cpp", "int main() {}\n")
+t.write("l.cpp", """\
 void
 #if defined(_WIN32)
 __declspec(dllexport)
 #endif
 foo() {}
 """)
-
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 lib l : l.cpp ;
 exe a : a.cpp l ;
 stage dist : a : <install-dependencies>on <install-type>EXE <install-type>LIB ;
 """)
-
 t.write("jamroot.jam", "")
-
 t.rm("dist")
 
 t.run_build_system()
@@ -138,17 +119,14 @@
 
 # Check that <use> properties are ignored the traversing target for staging.
 t.copy("l.cpp", "l2.cpp")
-
 t.copy("l.cpp", "l3.cpp")
-
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 lib l2 : l2.cpp ;
 lib l3 : l3.cpp ;
 lib l : l.cpp : <use>l2 <dependency>l3 ;
 exe a : a.cpp l ;
 stage dist : a : <install-dependencies>on <install-type>EXE <install-type>LIB ;
 """)
-
 t.rm("dist")
 
 t.run_build_system()
@@ -157,22 +135,18 @@
 
 # Check if <dependency> on 'stage' works.
 t.rm(".")
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 stage a1 : a1.txt : <location>dist ;
 stage a2 : a2.txt : <location>dist <dependency>a1 ;
 """)
 t.write("a1.txt", "")
 t.write("a2.txt", "")
-t.run_build_system("a2")
+t.run_build_system(["a2"])
 t.expect_addition(["dist/a1.txt", "dist/a2.txt"])
 
 # Regression test: check that <location>. works.
 t.rm(".")
-
-t.write("jamroot.jam", """
-stage a1 : d/a1.txt : <location>. ;
-""")
-
+t.write("jamroot.jam", "stage a1 : d/a1.txt : <location>. ;")
 t.write("d/a1.txt", "")
 
 t.run_build_system()
@@ -180,59 +154,38 @@
 
 # Test that relative paths of sources can be preserved.
 t.rm(".")
-
-t.write("jamroot.jam", """
-install dist : a/b/c.h : <install-source-root>. ;
-""")
-
+t.write("jamroot.jam", "install dist : a/b/c.h : <install-source-root>. ;")
 t.write("a/b/c.h", "")
 
 t.run_build_system()
 t.expect_addition("dist/a/b/c.h")
 
-t.write("jamroot.jam", """
-install dist : a/b/c.h : <install-source-root>a ;
-""")
-
+t.write("jamroot.jam", "install dist : a/b/c.h : <install-source-root>a ;")
 t.write("a/b/c.h", "")
 
 t.run_build_system()
 t.expect_addition("dist/b/c.h")
 
 t.rm(".")
-t.write("build/jamroot.jam", """
+t.write("build/jamroot.jam", """\
 install dist : ../a/b/c.h : <location>../dist <install-source-root>../a ;
 """)
-
 t.write("a/b/c.h", "")
 
 t.run_build_system(subdir="build")
 t.expect_addition("dist/b/c.h")
 
-t.write("jamroot.jam", """
-install dist2 : a/b/c.h : <install-source-root>a ;
-""")
-
+t.write("jamroot.jam", "install dist2 : a/b/c.h : <install-source-root>a ;")
 t.write("a/b/c.h", "")
-
-t.write("sub/jamfile.jam", """
-alias h : ..//dist2 ;
-""")
+t.write("sub/jamfile.jam", "alias h : ..//dist2 ;")
 
 t.run_build_system(subdir="sub")
 t.expect_addition("dist2/b/c.h")
 
 # Test that when installing .cpp files, we do not scan include dependencies.
 t.rm(".")
-
-t.write("jamroot.jam", """
-install dist : a.cpp ;
-""")
-
-t.write("a.cpp", """
-#include "a.h"
-""")
-
+t.write("jamroot.jam", "install dist : a.cpp ;")
+t.write("a.cpp", '#include "a.h"')
 t.write("a.h", "")
 
 t.run_build_system()
@@ -245,11 +198,7 @@
 
 # Test that <name> property works, when there is just one file in sources.
 t.rm(".")
-
-t.write("jamroot.jam", """
-install dist : a.cpp : <name>b.cpp ;
-""")
-
+t.write("jamroot.jam", "install dist : a.cpp : <name>b.cpp ;")
 t.write("a.cpp", "test file")
 
 t.run_build_system()

Modified: branches/release/tools/build/v2/test/standalone.py
==============================================================================
--- branches/release/tools/build/v2/test/standalone.py (original)
+++ branches/release/tools/build/v2/test/standalone.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,25 +2,21 @@
 
 # Copyright 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 
 # Regression tests: standalone project were not able to refer to targets
 # declared in themselves.
 
-t.write("a.cpp", """
-int main() {}
-""")
-
-t.write("jamroot.jam", """
-import standalone ;
-""")
-
-t.write("standalone.jam", """
+t.write("a.cpp", "int main() {}\n")
+t.write("jamroot.jam", "import standalone ;")
+t.write("standalone.jam", """\
+import alias ;
 import project ;
 
 project.initialize $(__name__) ;
@@ -32,7 +28,7 @@
 alias runtime : x ;
 """)
 
-t.write("standalone.py", """
+t.write("standalone.py", """\
 from b2.manager import get_manager
 
 # FIXME: this is ugly as death
@@ -49,9 +45,7 @@
 """)
 
 
-t.write("sub/jamfile.jam", """
-stage bin : /standalone//runtime ;
-""")
+t.write("sub/jamfile.jam", "stage bin : /standalone//runtime ;")
 
 t.run_build_system(subdir="sub")
 t.expect_addition("sub/bin/a.cpp")

Modified: branches/release/tools/build/v2/test/startup_v2.py
==============================================================================
--- branches/release/tools/build/v2/test/startup_v2.py (original)
+++ branches/release/tools/build/v2/test/startup_v2.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,74 +6,89 @@
 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
-import os
+import os.path
 import re
 
 
-def match_re(actual,expected):
- return re.match(expected,actual,re.DOTALL) != None
-
-# Test the v1 startup behavior.
-t = BoostBuild.Tester(match=match_re, boost_build_path='', pass_toolset=0)
-
-t.set_tree('startup')
-
-t.run_build_system(
- status=1, stdout=r'''Unable to load Boost\.Build: could not find "boost-build.jam"
-.*Attempted search from .* up to the root''', match = match_re)
-
-os.chdir('no-bootstrap1')
-
-t.run_build_system(
- status=1
- , stdout=r'''Unable to load Boost\.Build: could not find build system\.'''
- + r'''.*attempted to load the build system by invoking'''
- + r'''.*'boost-build ;'.*'''
- + r'''but we were unable to find "bootstrap\.jam"'''
- )
-
-# Descend to a subdirectory which /doesn't/ contain a boost-build.jam file, and
-# try again to test the crawl-up behavior.
-os.chdir('subdir')
-
-t.run_build_system(
- status=1
- , stdout=r'''Unable to load Boost\.Build: could not find build system\.'''
- + r'''.*attempted to load the build system by invoking'''
- + r'''.*'boost-build ;'.*'''
- + r'''but we were unable to find "bootstrap\.jam"'''
- )
-
-os.chdir('../../no-bootstrap2')
-
-t.run_build_system(
- status=1
- , stdout=r'''Unable to load Boost\.Build: could not find build system\.'''
- + r'''.*attempted to load the build system by invoking'''
- + r'''.*'boost-build \. ;'.*'''
- + r'''but we were unable to find "bootstrap\.jam"'''
- )
-
-os.chdir('../no-bootstrap3')
-
-t.run_build_system(
- status=1
- , stdout=r'''Unable to load Boost.Build
-.*boost-build.jam" was found.*
-However, it failed to call the "boost-build" rule'''
- )
+def check_for_existing_boost_build_jam(t):
+ """
+ This test depends on no boost-build.jam file existing in any of the
+ folders along the current folder's path. If it does exist, not only would
+ this test fail but it could point to a completely wrong Boost Build
+ installation, thus causing headaches when attempting to diagnose the
+ problem. That is why we explicitly check for this scenario.
+
+ """
+ problem = find_up_to_root(t.workdir, "boost-build.jam")
+ if problem:
+ BoostBuild.annotation("misconfiguration", """\
+This test expects to be run from a folder with no 'boost-build.jam' file in any
+of the folders along its path.
+
+Working folder:
+ '%s'
+
+Problematic boost-build.jam found at:
+ '%s'
+
+Please remove this file or change the test's working folder and rerun the test.
+""" % (t.workdir, problem))
+ t.fail_test(1, dump_stdio=False, dump_stack=False)
+
+
+def find_up_to_root(folder, name):
+ last = ""
+ while last != folder:
+ candidate = os.path.join(folder, name)
+ if os.path.exists(candidate):
+ return candidate
+ last = folder
+ folder = os.path.dirname(folder)
+
+
+def match_re(actual, expected):
+ return re.match(expected, actual, re.DOTALL) != None
+
+
+t = BoostBuild.Tester(match=match_re, boost_build_path="", pass_toolset=0)
+t.set_tree("startup")
+check_for_existing_boost_build_jam(t)
+
+t.run_build_system(status=1, stdout=
+r"""Unable to load Boost\.Build: could not find "boost-build\.jam"
+.*Attempted search from .* up to the root""")
+
+t.run_build_system(status=1, subdir="no-bootstrap1",
+ stdout=r"Unable to load Boost\.Build: could not find build system\."
+ r".*attempted to load the build system by invoking"
+ r".*'boost-build ;'"
+ r'.*but we were unable to find "bootstrap\.jam"')
+
+# Descend to a subdirectory which /does not/ contain a boost-build.jam file,
+# and try again to test the crawl-up behavior.
+t.run_build_system(status=1, subdir=os.path.join("no-bootstrap1", "subdir"),
+ stdout=r"Unable to load Boost\.Build: could not find build system\."
+ r".*attempted to load the build system by invoking"
+ r".*'boost-build ;'"
+ r'.*but we were unable to find "bootstrap\.jam"')
+
+t.run_build_system(status=1, subdir="no-bootstrap2",
+ stdout=r"Unable to load Boost\.Build: could not find build system\."
+ r".*attempted to load the build system by invoking"
+ r".*'boost-build \. ;'"
+ r'.*but we were unable to find "bootstrap\.jam"')
+
+t.run_build_system(status=1, subdir='no-bootstrap3', stdout=
+r"""Unable to load Boost.Build
+.*boost-build\.jam" was found.*
+However, it failed to call the "boost-build" rule""")
 
 # Test bootstrapping based on BOOST_BUILD_PATH.
-os.chdir('../bootstrap-env')
-t.run_build_system(
- extra_args = '-sBOOST_BUILD_PATH=../boost-root/build'
- , stdout = 'build system bootstrapped'
- )
+t.run_build_system(["-sBOOST_BUILD_PATH=../boost-root/build"],
+ subdir="bootstrap-env", stdout="build system bootstrapped")
 
 # Test bootstrapping based on an explicit path in boost-build.jam.
-os.chdir('../bootstrap-explicit')
-t.run_build_system(
- stdout = 'build system bootstrapped'
- )
+t.run_build_system(subdir="bootstrap-explicit",
+ stdout="build system bootstrapped")
 
 t.cleanup()

Copied: branches/release/tools/build/v2/test/static_and_shared_library.py (from r78961, /trunk/tools/build/v2/test/static_and_shared_library.py)
==============================================================================
--- /trunk/tools/build/v2/test/static_and_shared_library.py (original)
+++ branches/release/tools/build/v2/test/static_and_shared_library.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,10 +6,8 @@
 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
-import os.path
-import shutil
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 t.write("jamroot.jam", "")
 t.write("lib/c.cpp", "int bar() { return 0; }\n")
 t.write("lib/jamfile.jam", """\
@@ -18,7 +16,7 @@
 """)
 
 def reset():
- shutil.rmtree(os.path.join(t.workdir, "lib", "bin"))
+ t.rm("lib/bin")
 
 t.run_build_system(subdir='lib')
 t.expect_addition("lib/bin/$toolset/debug/" * BoostBuild.List("c.obj "
@@ -26,13 +24,13 @@
 t.expect_nothing_more()
 
 reset()
-t.run_build_system(subdir='lib', extra_args="link=shared")
+t.run_build_system(["link=shared"], subdir="lib")
 t.expect_addition("lib/bin/$toolset/debug/" * BoostBuild.List("c.obj "
     "auxilliary1.lib auxilliary2.dll"))
 t.expect_nothing_more()
 
 reset()
-t.run_build_system(subdir='lib', extra_args="link=static")
+t.run_build_system(["link=static"], subdir="lib")
 t.expect_addition("lib/bin/$toolset/debug/link-static/" * BoostBuild.List(
     "c.obj auxilliary1.lib auxilliary2.lib"))
 t.expect_nothing_more()

Deleted: branches/release/tools/build/v2/test/svn_tree.py
==============================================================================
--- branches/release/tools/build/v2/test/svn_tree.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
+++ (empty file)
@@ -1,668 +0,0 @@
-#!/usr/bin/env python
-#
-# tree.py: tools for comparing directory trees
-#
-# Subversion is a tool for revision control.
-# See http://subversion.tigris.org for more information.
-#
-# ====================================================================
-# Copyright (c) 2001 Sam Tobin-Hochstadt. All rights reserved.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://subversion.tigris.org/license-1.html.
-# If newer versions of this license are posted there, you may use a
-# newer version instead, at your option.
-#
-######################################################################
-
-# This file was modified by Vladimir Prus to store modification times in tree
-# nodes.
-
-import re
-import string
-import os.path
-import os
-import stat
-
-
-#========================================================================
-
-# ===> Overview of our Datastructures <===
-
-# The general idea here is that many, many things can be represented by
-# a tree structure:
-
-# - a working copy's structure and contents
-# - the output of 'svn status'
-# - the output of 'svn checkout/update'
-# - the output of 'svn commit'
-
-# The idea is that a test function creates a "expected" tree of some
-# kind, and is then able to compare it to an "actual" tree that comes
-# from running the Subversion client. This is what makes a test
-# automated; if an actual and expected tree match exactly, then the test
-# has passed. (See compare_trees() below.)
-
-# The SVNTreeNode class is the fundamental data type used to build tree
-# structures. The class contains a method for "dropping" a new node
-# into an ever-growing tree structure. (See also create_from_path()).
-
-# We have four parsers in this file for the four use cases listed above:
-# each parser examines some kind of input and returns a tree of
-# SVNTreeNode objects. (See build_tree_from_checkout(),
-# build_tree_from_commit(), build_tree_from_status(), and
-# build_tree_from_wc()). These trees are the "actual" trees that result
-# from running the Subversion client.
-
-# Also necessary, of course, is a convenient way for a test to create an
-# "expected" tree. The test *could* manually construct and link a bunch
-# of SVNTreeNodes, certainly. But instead, all the tests are using the
-# build_generic_tree() routine instead.
-
-# build_generic_tree() takes a specially-formatted list of lists as
-# input, and returns a tree of SVNTreeNodes. The list of lists has this
-# structure:
-
-# [ ['/full/path/to/item', 'text contents', {prop-hash}, {att-hash}],
-# [...],
-# [...],
-# ... ]
-
-# You can see that each item in the list essentially defines an
-# SVNTreeNode. build_generic_tree() instantiates a SVNTreeNode for each
-# item, and then drops it into a tree by parsing each item's full path.
-
-# So a typical test routine spends most of its time preparing lists of
-# this format and sending them to build_generic_tree(), rather than
-# building the "expected" trees directly.
-
-# ### Note: in the future, we'd like to remove this extra layer of
-# ### abstraction. We'd like the SVNTreeNode class to be more
-# ### directly programmer-friendly, providing a number of accessor
-# ### routines, so that tests can construct trees directly.
-
-# The first three fields of each list-item are self-explanatory. It's
-# the fourth field, the "attribute" hash, that needs some explanation.
-# The att-hash is used to place extra information about the node itself,
-# depending on the parsing context:
-
-# - in the 'svn co/up' use-case, each line of output starts with two
-# characters from the set of (A, D, G, U, C, _). This status code
-# is stored in a attribute named 'status'.
-
-# - in the 'svn ci/im' use-case, each line of output starts with one
-# of the words (Adding, Deleting, Sending). This verb is stored in
-# an attribute named 'verb'.
-
-# - in the 'svn status' use-case (which is always run with the -v
-# (--verbose) flag), each line of output contains a working revision
-# number and a two-letter status code similar to the 'svn co/up'
-# case. The repository revision is also printed. All of this
-# information is stored in attributes named 'wc_rev', 'status', and
-# 'repos_rev', respectively.
-
-# - in the working-copy use-case, the att-hash is ignored.
-
-
-# Finally, one last explanation: the file 'actions.py' contain a number
-# of helper routines named 'run_and_verify_FOO'. These routines take
-# one or more "expected" trees as input, then run some svn subcommand,
-# then push the output through an appropriate parser to derive an
-# "actual" tree. Then it runs compare_trees() and returns the result.
-# This is why most tests typically end with a call to
-# run_and_verify_FOO().
-
-
-
-
-# A node in a tree.
-#
-# If CHILDREN is None, then the node is a file. Otherwise, CHILDREN
-# is a list of the nodes making up that directory's children.
-#
-# NAME is simply the name of the file or directory. CONTENTS is a
-# string that contains the file's contents (if a file), PROPS are
-# properties attached to files or dirs, and ATTS is a dictionary of
-# other metadata attached to the node.
-
-class SVNTreeNode:
-
- def __init__(self, name, children=None, contents=None, props={}, atts={}):
- self.name = name
- self.mtime = 0
- self.children = children
- self.contents = contents
- self.props = props
- self.atts = atts
- self.path = name
-
-# TODO: Check to make sure contents and children are mutually exclusive
-
- def add_child(self, newchild):
- if self.children is None: # if you're a file,
- self.children = [] # become an empty dir.
- child_already_exists = 0
- for a in self.children:
- if a.name == newchild.name:
- child_already_exists = 1
- break
- if child_already_exists == 0:
- self.children.append(newchild)
- newchild.path = os.path.join (self.path, newchild.name)
-
- # If you already have the node,
- else:
- if newchild.children is None:
- # this is the 'end' of the chain, so copy any content here.
- a.contents = newchild.contents
- a.props = newchild.props
- a.atts = newchild.atts
- a.path = os.path.join (self.path, newchild.name)
- else:
- # try to add dangling children to your matching node
- for i in newchild.children:
- a.add_child(i)
-
-
- def pprint(self):
- print " * Node name: ", self.name
- print " Path: ", self.path
- print " Contents: ", self.contents
- print " Properties:", self.props
- print " Attributes:", self.atts
- ### FIXME: I'd like to be able to tell the difference between
- ### self.children is None (file) and self.children == [] (empty
- ### diretory), but it seems that most places that construct
- ### SVNTreeNode objects don't even try to do that. --xbc
- if self.children is not None:
- print " Children: ", len(self.children)
- else:
- print " Children: is a file."
-
-# reserved name of the root of the tree
-
-root_node_name = "__SVN_ROOT_NODE"
-
-# Exception raised if you screw up in this module.
-
-class SVNTreeError(Exception): pass
-
-# Exception raised if two trees are unequal
-
-class SVNTreeUnequal(Exception): pass
-
-# Exception raised if one node is file and other is dir
-
-class SVNTypeMismatch(Exception): pass
-
-# Exception raised if get_child is passed a file.
-
-class SVNTreeIsNotDirectory(Exception): pass
-
-
-# Some attributes 'stack' on each other if the same node is added
-# twice to a tree. Place all such special cases in here.
-def attribute_merge(orighash, newhash):
- "Merge the attributes in NEWHASH into ORIGHASH."
-
- if orighash.has_key('verb') and newhash.has_key('verb'):
- # Special case: if a commit reports a node as "deleted", then
- # "added", it's a replacment.
- if orighash['verb'] == "Deleting":
- if newhash['verb'] == "Adding":
- orighash['verb'] = "Replacing"
-
- # Add future stackable attributes here...
-
- return orighash
-
-
-# helper func
-def add_elements_as_path(top_node, element_list):
- """Add the elements in ELEMENT_LIST as if they were a single path
- below TOP_NODE."""
-
- # The idea of this function is to take a list like so:
- # ['A', 'B', 'C'] and a top node, say 'Z', and generate a tree
- # like this:
- #
- # Z -> A -> B -> C
- #
- # where 1 -> 2 means 2 is a child of 1.
- #
-
- prev_node = top_node
- for i in element_list:
- new_node = SVNTreeNode(i, None)
- prev_node.add_child(new_node)
- prev_node = new_node
-
-
-# Sorting function -- sort 2 nodes by their names.
-def node_is_greater(a, b):
- "Sort the names of two nodes."
- # Interal use only
- if a.name == b.name:
- return 0
- if a.name > b.name:
- return 1
- else:
- return -1
-
-
-# Helper for compare_trees
-def compare_file_nodes(a, b):
- """Compare two nodes' names, contents, and properties, ignoring
- children. Return 0 if the same, 1 otherwise."""
- if a.name != b.name:
- return 1
- if a.contents != b.contents:
- return 1
- if a.props != b.props:
- return 1
- if a.atts != b.atts:
- return 1
-
-
-# Internal utility used by most build_tree_from_foo() routines.
-#
-# (Take the output and .add_child() it to a root node.)
-
-def create_from_path(path, contents=None, props={}, atts={}):
- """Create and return a linked list of treenodes, given a PATH
- representing a single entry into that tree. CONTENTS and PROPS are
- optional arguments that will be deposited in the tail node."""
-
- # get a list of all the names in the path
- # each of these will be a child of the former
- elements = path.split("/")
- if len(elements) == 0:
- raise SVNTreeError
-
- root_node = SVNTreeNode(elements[0], None)
-
- add_elements_as_path(root_node, elements[1:])
-
- # deposit contents in the very last node.
- node = root_node
- while 1:
- if node.children is None:
- node.contents = contents
- node.props = props
- node.atts = atts
- break
- node = node.children[0]
-
- return root_node
-
-
-# helper for handle_dir(), which is a helper for build_tree_from_wc()
-def get_props(path):
- "Return a hash of props for PATH, using the svn client."
-
- # It's not kosher to look inside SVN/ and try to read the internal
- # property storage format. Instead, we use 'svn proplist'. After
- # all, this is the only way the user can retrieve them, so we're
- # respecting the black-box paradigm.
-
- props = {}
- output, errput = main.run_svn(1, "proplist", path, "--verbose")
-
- for line in output:
- name, value = line.split(' : ')
- name = string.strip(name)
- value = string.strip(value)
- props[name] = value
-
- return props
-
-
-# helper for handle_dir(), which helps build_tree_from_wc()
-def get_text(path):
- "Return a string with the textual contents of a file at PATH."
-
- # sanity check
- if not os.path.isfile(path):
- return None
-
- fp = open(path, 'r')
- contents = fp.read()
- fp.close()
- return contents
-
-
-# main recursive helper for build_tree_from_wc()
-def handle_dir(path, current_parent, load_props, ignore_svn):
-
- # get a list of all the files
- all_files = os.listdir(path)
- files = []
- dirs = []
-
- # put dirs and files in their own lists, and remove SVN dirs
- for f in all_files:
- f = os.path.join(path, f)
- if (os.path.isdir(f) and os.path.basename(f) != 'SVN'):
- dirs.append(f)
- elif os.path.isfile(f):
- files.append(f)
-
- # add each file as a child of CURRENT_PARENT
- for f in files:
- fcontents = get_text(f)
- if load_props:
- fprops = get_props(f)
- else:
- fprops = {}
- c = SVNTreeNode(os.path.basename(f), None,
- fcontents, fprops)
- c.mtime = os.stat(f)[stat.ST_MTIME]
- current_parent.add_child(c)
-
- # for each subdir, create a node, walk its tree, add it as a child
- for d in dirs:
- if load_props:
- dprops = get_props(d)
- else:
- dprops = {}
- new_dir_node = SVNTreeNode(os.path.basename(d), [], None, dprops)
- handle_dir(d, new_dir_node, load_props, ignore_svn)
- new_dir_node.mtime = os.stat(f)[stat.ST_MTIME]
- current_parent.add_child(new_dir_node)
-
-def get_child(node, name):
- """If SVNTreeNode NODE contains a child named NAME, return child;
- else, return None. If SVNTreeNode is not a directory, raise a
- SVNTreeIsNotDirectory exception"""
- if node.children == None:
- raise SVNTreeIsNotDirectory
- for n in node.children:
- if (name == n.name):
- return n
- return None
-
-
-# Helper for compare_trees
-def default_singleton_handler(a, baton):
- "Printing SVNTreeNode A's name, then raise SVNTreeUnequal."
- print "Got singleton", a.name
- a.pprint()
- raise SVNTreeUnequal
-
-
-###########################################################################
-###########################################################################
-# EXPORTED ROUTINES ARE BELOW
-
-
-# Main tree comparison routine!
-
-def compare_trees(a, b,
- singleton_handler_a = None,
- a_baton = None,
- singleton_handler_b = None,
- b_baton = None):
- """Compare SVNTreeNodes A and B, expressing differences using FUNC_A
- and FUNC_B. FUNC_A and FUNC_B are functions of two arguments (a
- SVNTreeNode and a context baton), and may raise exception
- SVNTreeUnequal. Their return value is ignored.
-
- If A and B are both files, then return 0 if their contents,
- properties, and names are all the same; else raise a SVNTreeUnequal.
- If A is a file and B is a directory, raise a SVNTypeMismatch; same
- vice-versa. If both are directories, then for each entry that
- exists in both, call compare_trees on the two entries; otherwise, if
- the entry exists only in A, invoke FUNC_A on it, and likewise for
- B with FUNC_B."""
-
- def display_nodes(a, b):
- 'Display two nodes, expected and actual.'
- print "============================================================="
- print "Expected", b.name, "and actual", a.name, "are different!"
- print "============================================================="
- print "EXPECTED NODE TO BE:"
- print "============================================================="
- b.pprint()
- print "============================================================="
- print "ACTUAL NODE FOUND:"
- print "============================================================="
- a.pprint()
-
- # Setup singleton handlers
- if (singleton_handler_a is None):
- singleton_handler_a = default_singleton_handler
- if (singleton_handler_b is None):
- singleton_handler_b = default_singleton_handler
-
- try:
- # A and B are both files.
- if ((a.children is None) and (b.children is None)):
- if compare_file_nodes(a, b):
- display_nodes(a, b)
- raise main.SVNTreeUnequal
- # One is a file, one is a directory.
- elif (((a.children is None) and (b.children is not None))
- or ((a.children is not None) and (b.children is None))):
- display_nodes(a, b)
- raise main.SVNTypeMismatch
- # They're both directories.
- else:
- # First, compare the directories' two hashes.
- if (a.props != b.props) or (a.atts != b.atts):
- display_nodes(a, b)
- raise main.SVNTreeUnequal
-
- accounted_for = []
- # For each child of A, check and see if it's in B. If so, run
- # compare_trees on the two children and add b's child to
- # accounted_for. If not, run FUNC_A on the child. Next, for each
- # child of B, check and see if it's in accounted_for. If it is,
- # do nothing. If not, run FUNC_B on it.
- for a_child in a.children:
- b_child = get_child(b, a_child.name)
- if b_child:
- accounted_for.append(b_child)
- compare_trees(a_child, b_child,
- singleton_handler_a, a_baton,
- singleton_handler_b, b_baton)
- else:
- singleton_handler_a(a_child, a_baton)
- for b_child in b.children:
- if (b_child not in accounted_for):
- singleton_handler_b(b_child, b_baton)
- return 0
- except SVNTypeMismatch:
- print 'Unequal Types: one Node is a file, the other is a directory'
- raise SVNTreeUnequal
- except SVNTreeIsNotDirectory:
- print "Error: Foolish call to get_child."
- sys.exit(1)
- except IndexError:
- print "Error: unequal number of children"
- raise SVNTreeUnequal
- except SVNTreeUnequal:
- if a.name == root_node_name:
- return 1
- else:
- print "Unequal at node %s" % a.name
- raise SVNTreeUnequal
- return 0
-
-
-
-
-# Visually show a tree's structure
-
-def dump_tree(n,indent=""):
- "Print out a nice representation of the tree's structure."
-
- # Code partially stolen from Dave Beazley.
- if n.children is None:
- tmp_children = []
- else:
- tmp_children = n.children
-
- if n.name == root_node_name:
- print "%s%s" % (indent, "ROOT")
- else:
- print "%s%s" % (indent, n.name)
-
- indent = indent.replace("-", " ")
- indent = indent.replace("+", " ")
- for i in range(len(tmp_children)):
- c = tmp_children[i]
- if i == len(tmp_children) - 1:
- dump_tree(c,indent + " +-- ")
- else:
- dump_tree(c,indent + " |-- ")
-
-
-###################################################################
-###################################################################
-# PARSERS that return trees made of SVNTreeNodes....
-
-
-###################################################################
-# Build an "expected" static tree from a list of lists
-
-
-# Create a list of lists, of the form:
-#
-# [ [path, contents, props, atts], ... ]
-#
-# and run it through this parser. PATH is a string, a path to the
-# object. CONTENTS is either a string or None, and PROPS and ATTS are
-# populated dictionaries or {}. Each CONTENTS/PROPS/ATTS will be
-# attached to the basename-node of the associated PATH.
-
-def build_generic_tree(nodelist):
- "Given a list of lists of a specific format, return a tree."
-
- root = SVNTreeNode(root_node_name)
-
- for list in nodelist:
- new_branch = create_from_path(list[0], list[1], list[2], list[3])
- root.add_child(new_branch)
-
- return root
-
-
-####################################################################
-# Build trees from different kinds of subcommand output.
-
-
-# Parse co/up output into a tree.
-#
-# Tree nodes will contain no contents, and only one 'status' att.
-
-def build_tree_from_checkout(lines):
- "Return a tree derived by parsing the output LINES from 'co' or 'up'."
-
- root = SVNTreeNode(root_node_name)
- rm = re.compile ('^([MAGCUD_ ][MAGCUD_ ]) (.+)')
-
- for line in lines:
- match = rm.search(line)
- if match and match.groups():
- new_branch = create_from_path(match.group(2), None, {},
- {'status' : match.group(1)})
- root.add_child(new_branch)
-
- return root
-
-
-# Parse ci/im output into a tree.
-#
-# Tree nodes will contain no contents, and only one 'verb' att.
-
-def build_tree_from_commit(lines):
- "Return a tree derived by parsing the output LINES from 'ci' or 'im'."
-
- # Lines typically have a verb followed by whitespace then a path.
- root = SVNTreeNode(root_node_name)
- rm1 = re.compile ('^(\w+)\s+(.+)')
- rm2 = re.compile ('^Transmitting')
-
- for line in lines:
- match = rm2.search(line)
- if not match:
- match = rm1.search(line)
- if match and match.groups():
- new_branch = create_from_path(match.group(2), None, {},
- {'verb' : match.group(1)})
- root.add_child(new_branch)
-
- return root
-
-
-# Parse status output into a tree.
-#
-# Tree nodes will contain no contents, and these atts:
-#
-# 'status', 'wc_rev', 'repos_rev'
-# ... and possibly 'locked', 'copied', IFF columns non-empty.
-#
-
-def build_tree_from_status(lines):
- "Return a tree derived by parsing the output LINES from 'st'."
-
- root = SVNTreeNode(root_node_name)
- rm = re.compile ('^.+\:.+(\d+)')
- lastline = string.strip(lines.pop())
- match = rm.search(lastline)
- if match and match.groups():
- repos_rev = match.group(1)
- else:
- repos_rev = '?'
-
- # Try http://www.wordsmith.org/anagram/anagram.cgi?anagram=ACDRMGU
- rm = re.compile ('^([MACDRUG_ ][MACDRUG_ ])(.)(.) . [^0-9-]+(\d+|-)(.{23})(.+)')
- for line in lines:
- match = rm.search(line)
- if match and match.groups():
- if match.group(5) != '-': # ignore items that only exist on repos
- atthash = {'status' : match.group(1),
- 'wc_rev' : match.group(4),
- 'repos_rev' : repos_rev}
- if match.group(2) != ' ':
- atthash['locked'] = match.group(2)
- if match.group(3) != ' ':
- atthash['copied'] = match.group(3)
- new_branch = create_from_path(match.group(6), None, {}, atthash)
-
- root.add_child(new_branch)
-
- return root
-
-
-####################################################################
-# Build trees by looking at the working copy
-
-
-# The reason the 'load_props' flag is off by default is because it
-# creates a drastic slowdown -- we spawn a new 'svn proplist'
-# process for every file and dir in the working copy!
-
-
-def build_tree_from_wc(wc_path, load_props=0, ignore_svn=1):
- """Takes WC_PATH as the path to a working copy. Walks the tree below
- that path, and creates the tree based on the actual found
- files. If IGNORE_SVN is true, then exclude SVN dirs from the tree.
- If LOAD_PROPS is true, the props will be added to the tree."""
-
- root = SVNTreeNode(root_node_name, None)
-
- # if necessary, store the root dir's props in the root node.
- if load_props:
- root.props = get_props(wc_path)
-
- # Walk the tree recursively
- handle_dir(os.path.normpath(wc_path), root, load_props, ignore_svn)
-
- return root
-
-### End of file.
-# local variables:
-# eval: (load-file "../../../../../tools/dev/svn-dev.el")
-# end:

Modified: branches/release/tools/build/v2/test/symlink.py
==============================================================================
--- branches/release/tools/build/v2/test/symlink.py (original)
+++ branches/release/tools/build/v2/test/symlink.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -17,7 +17,7 @@
     sys.exit(1)
 
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamroot.jam", "import gcc ;")
 

Modified: branches/release/tools/build/v2/test/tag.py
==============================================================================
--- branches/release/tools/build/v2/test/tag.py (original)
+++ branches/release/tools/build/v2/test/tag.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,32 +1,33 @@
 #!/usr/bin/python
 
-# Copyright (C) Pedro Ferreira 2003. Permission to copy, use, modify, sell and
-# distribute this software is granted provided this copyright notice appears in
-# all copies. This software is provided "as is" without express or implied
-# warranty, and with no claim as to its suitability for any purpose.
+# Copyright (C) 2003. Pedro Ferreira
+# 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 BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # test_folder_with_dot_in_name()
 # ------------------------------
 #
-################################################################################
+###############################################################################
 
 def test_folder_with_dot_in_name(t):
- """ Regression test: the 'tag' feature did not work in directories that had
- a dot in their name.
     """
+ Regression test: the 'tag' feature did not work in directories that had a
+ dot in their name.
 
- t.write("version-1.32.0/jamroot.jam", """
+ """
+ t.write("version-1.32.0/jamroot.jam", """\
 project test : requirements <tag>@$(__name__).tag ;
 
 rule tag ( name : type ? : property-set )
 {
    # Do nothing, just make sure the rule is invoked OK.
- ECHO "The tag rule has been invoked." ;
+ ECHO The tag rule has been invoked. ;
 }
 exe a : a.cpp ;
 """)
@@ -34,21 +35,20 @@
 
     t.run_build_system(subdir="version-1.32.0")
     t.expect_addition("version-1.32.0/bin/$toolset/debug/a.exe")
- t.expect_output_line("The tag rule has been invoked.")
+ t.expect_output_lines("The tag rule has been invoked.")
 
 
-################################################################################
+###############################################################################
 #
 # test_tag_property()
 # -------------------
 #
-################################################################################
+###############################################################################
 
 def test_tag_property(t):
- """Basic tag property test.
- """
+ """Basic tag property test."""
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 import virtual-target ;
 
 rule tag ( name : type ? : property-set )
@@ -77,44 +77,44 @@
 stage c : a ;
 """)
 
- t.write("a.cpp", """
+ t.write("a.cpp", """\
 int main() {}
 #ifdef _MSC_VER
 __declspec (dllexport) void x () {}
 #endif
 """)
 
- file_list = \
- BoostBuild.List("bin/$toolset/debug/a_ds.exe") + \
- BoostBuild.List("bin/$toolset/debug/b_ds.dll") + \
- BoostBuild.List("c/a_ds.exe") + \
- BoostBuild.List("bin/$toolset/release/a_rs.exe") + \
- BoostBuild.List("bin/$toolset/release/b_rs.dll") + \
- BoostBuild.List("c/a_rs.exe") + \
- BoostBuild.List("bin/$toolset/debug/link-static/a_dt.exe") + \
- BoostBuild.List("bin/$toolset/debug/link-static/b_dt.lib") + \
- BoostBuild.List("c/a_dt.exe") + \
- BoostBuild.List("bin/$toolset/release/link-static/a_rt.exe") + \
- BoostBuild.List("bin/$toolset/release/link-static/b_rt.lib") + \
- BoostBuild.List("c/a_rt.exe")
+ file_list = (
+ BoostBuild.List("bin/$toolset/debug/a_ds.exe") +
+ BoostBuild.List("bin/$toolset/debug/b_ds.dll") +
+ BoostBuild.List("c/a_ds.exe") +
+ BoostBuild.List("bin/$toolset/release/a_rs.exe") +
+ BoostBuild.List("bin/$toolset/release/b_rs.dll") +
+ BoostBuild.List("c/a_rs.exe") +
+ BoostBuild.List("bin/$toolset/debug/link-static/a_dt.exe") +
+ BoostBuild.List("bin/$toolset/debug/link-static/b_dt.lib") +
+ BoostBuild.List("c/a_dt.exe") +
+ BoostBuild.List("bin/$toolset/release/link-static/a_rt.exe") +
+ BoostBuild.List("bin/$toolset/release/link-static/b_rt.lib") +
+ BoostBuild.List("c/a_rt.exe"))
 
- variants = "debug release link=static,shared"
+ variants = ["debug", "release", "link=static,shared"]
 
     t.run_build_system(variants)
     t.expect_addition(file_list)
 
- t.run_build_system(variants + " clean")
+ t.run_build_system(variants + ["clean"])
     t.expect_removal(file_list)
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 test_tag_property(t)
 test_folder_with_dot_in_name(t)

Modified: branches/release/tools/build/v2/test/test_all.py
==============================================================================
--- branches/release/tools/build/v2/test/test_all.py (original)
+++ branches/release/tools/build/v2/test/test_all.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -6,10 +6,11 @@
 # (See accompanying file LICENSE_1_0.txt or copy at
 # http://www.boost.org/LICENSE_1_0.txt)
 
+import BoostBuild
+
 import os
+import os.path
 import sys
-import string
-import BoostBuild
 
 xml = "--xml" in sys.argv
 toolset = BoostBuild.get_toolset()
@@ -17,8 +18,8 @@
 
 # Clear environment for testing.
 #
-for s in ('BOOST_ROOT', 'BOOST_BUILD_PATH', 'JAM_TOOLSET', 'BCCROOT', 'MSVCDir',
- 'MSVC', 'MSVCNT', 'MINGW', 'watcom' ):
+for s in ("BOOST_ROOT", "BOOST_BUILD_PATH", "JAM_TOOLSET", "BCCROOT",
+ "MSVCDir", "MSVC", "MSVCNT", "MINGW", "watcom"):
     try:
         del os.environ[s]
     except:
@@ -28,69 +29,93 @@
 
 
 def run_tests(critical_tests, other_tests):
- """Runs first critical tests and then other_tests.
+ """
+ Runs first the critical_tests and then the other_tests.
+
+ Writes the name of the first failed test to test_results.txt. Critical
+ tests are run in the specified order, other tests are run starting with the
+ one that failed first on the last test run.
 
- Stops on first error, and write the name of failed test to
- test_results.txt. Critical tests are run in the specified order, other
- tests are run starting with the one that failed the last time.
     """
     last_failed = last_failed_test()
     other_tests = reorder_tests(other_tests, last_failed)
     all_tests = critical_tests + other_tests
 
     invocation_dir = os.getcwd()
+ max_test_name_len = 10
+ for x in all_tests:
+ if len(x) > max_test_name_len:
+ max_test_name_len = len(x)
 
     pass_count = 0
     failures_count = 0
 
- for i in all_tests:
- passed = 1
+ for test in all_tests:
         if not xml:
- print ("%-25s : " %(i)),
+ print("%%-%ds :" % max_test_name_len % test),
+
+ passed = 0
         try:
- __import__(i)
+ __import__(test)
+ passed = 1
+ except KeyboardInterrupt:
+ """This allows us to abort the testing manually using Ctrl-C."""
+ raise
         except SystemExit:
- passed = 0;
- if failures_count == 0:
- f = open(os.path.join(invocation_dir, 'test_results.txt'), 'w')
- f.write(i)
- f.close()
- failures_count = failures_count + 1
- # Restore the current directory, which might be changed by the test.
- os.chdir(invocation_dir)
+ """This is the regular way our test scripts are supposed to report
+ test failures."""
+ except:
+ exc_type, exc_value, exc_tb = sys.exc_info()
+ try:
+ BoostBuild.annotation("failure - unhandled exception", "%s - "
+ "%s" % (exc_type.__name__, exc_value))
+ BoostBuild.annotate_stack_trace(exc_tb)
+ finally:
+ # Explicitly clear a hard-to-garbage-collect traceback
+ # related reference cycle as per documented sys.exc_info()
+ # usage suggestion.
+ del exc_tb
+
+ if passed:
+ pass_count += 1
+ else:
+ failures_count += 1
+ if failures_count == 1:
+ f = open(os.path.join(invocation_dir, "test_results.txt"), "w")
+ try:
+ f.write(test)
+ finally:
+ f.close()
+
+ # Restore the current directory, which might have been changed by the
+ # test.
+ os.chdir(invocation_dir)
 
         if not xml:
             if passed:
- print "PASSED"
+ print("PASSED")
             else:
- print "FAILED"
-
- if i == "regression":
- BoostBuild.flush_annotations()
- BoostBuild.clear_annotations()
+ print("FAILED")
         else:
             rs = "succeed"
             if not passed:
                 rs = "fail"
             print """
 <test-log library="build" test-name="%s" test-type="run" toolset="%s" test-program="%s" target-directory="%s">
-<run result="%s">""" % (i, toolset, "tools/build/v2/test/" + i + ".py",
- "boost/bin.v2/boost.build.tests/" + toolset + "/" + i, rs)
-
+<run result="%s">""" % (test, toolset, "tools/build/v2/test/" + test + ".py",
+ "boost/bin.v2/boost.build.tests/" + toolset + "/" + test, rs)
             if not passed:
                 BoostBuild.flush_annotations(1)
-
             print """
 </run>
 </test-log>
 """
- if passed:
- pass_count = pass_count + 1
         sys.stdout.flush() # Makes testing under emacs more entertaining.
+ BoostBuild.clear_annotations()
 
     # Erase the file on success.
     if failures_count == 0:
- open('test_results.txt', 'w')
+ open("test_results.txt", "w").close()
 
     if not xml:
         print """
@@ -101,143 +126,163 @@
 
 
 def last_failed_test():
- "Returns the name of last failed test or None"
+ "Returns the name of the last failed test or None."
     try:
         f = open("test_results.txt")
- s = string.strip(f.read())
- return s
- except:
+ try:
+ return f.read().strip()
+ finally:
+ f.close()
+ except Exception:
         return None
 
 
 def reorder_tests(tests, first_test):
     try:
         n = tests.index(first_test)
- return [first_test] + tests[:n] + tests[n+1:]
+ return [first_test] + tests[:n] + tests[n + 1:]
     except ValueError:
         return tests
 
 
-critical_tests = ["unit_tests", "module_actions", "startup_v2"]
-
-critical_tests += ["core_d12", "core_typecheck", "core_delete_module",
- "core_language", "core_arguments", "core_varnames", "core_import_module"]
-
-tests = [ "absolute_sources",
- "alias",
- "alternatives",
- "bad_dirname",
- "build_dir",
- "build_file",
- "build_no",
- "builtin_echo",
- "builtin_exit",
- "c_file",
- "chain",
- "clean",
- "composite",
- "conditionals",
- "conditionals2",
- "conditionals3",
- "conditionals_multiple",
- "configuration",
- "copy_time",
- "core_action_status",
- "core_actions_quietly",
- "core_at_file",
- "core_bindrule",
- "core_nt_line_length",
- "core_option_d2",
- "core_option_l",
- "core_option_n",
- "core_parallel_actions",
- "core_parallel_multifile_actions_1",
- "core_parallel_multifile_actions_2",
- "core_update_now",
- "custom_generator",
- "default_build",
- "default_features",
+critical_tests = ["unit_tests", "module_actions", "startup_v2", "core_d12",
+ "core_typecheck", "core_delete_module", "core_language", "core_arguments",
+ "core_varnames", "core_import_module"]
+
+# We want to collect debug information about the test site before running any
+# of the tests, but only when not running the tests interactively. Then the
+# user can easily run this always-failing test directly to see what it would
+# have returned and there is no need to have it spoil a possible 'all tests
+# passed' result.
+if xml:
+ critical_tests.insert(0, "collect_debug_info")
+
+tests = ["absolute_sources",
+ "alias",
+ "alternatives",
+ "bad_dirname",
+ "build_dir",
+ "build_file",
+ "build_no",
+ "builtin_echo",
+ "builtin_exit",
+ "builtin_split_by_characters",
+ "c_file",
+ "chain",
+ "clean",
+ "composite",
+ "conditionals",
+ "conditionals2",
+ "conditionals3",
+ "conditionals_multiple",
+ "configuration",
+ "copy_time",
+ "core_action_output",
+ "core_action_status",
+ "core_actions_quietly",
+ "core_at_file",
+ "core_bindrule",
+ "core_nt_cmd_line",
+ "core_option_d2",
+ "core_option_l",
+ "core_option_n",
+ "core_parallel_actions",
+ "core_parallel_multifile_actions_1",
+ "core_parallel_multifile_actions_2",
+ "core_source_line_tracking",
+ "core_update_now",
+ "core_variables_in_actions",
+ "custom_generator",
+ "default_build",
+ "default_features",
 # This test is known to be broken itself.
-# "default_toolset",
- "dependency_property",
- "dependency_test",
- "direct_request_test",
- "disambiguation",
- "dll_path",
- "double_loading",
- "duplicate",
- "example_libraries",
- "example_make",
- "expansion",
- "explicit",
- "free_features_request",
- "generator_selection",
- "generators_test",
- "implicit_dependency",
- "indirect_conditional",
- "inherit_toolset",
- "inherited_dependency",
- "inline",
- "lib_source_property",
- "library_chain",
- "library_property",
- "load_order",
- "loop",
- "make_rule",
- "ndebug",
- "no_type",
- "notfile",
- "ordered_include",
- "out_of_tree",
- "path_features",
- "prebuilt",
- "print",
- "project_dependencies",
- "project_glob",
- "project_root_constants",
- "project_root_rule",
- "project_test3",
- "project_test4",
- "property_expansion",
- "rebuilds",
- "regression",
- "relative_sources",
- "remove_requirement",
- "resolution",
- "searched_lib",
- "skipping",
- "sort_rule",
- "source_locations",
- "stage",
- "standalone",
- "suffix",
- "tag",
- "test_result_dumping",
- "testing_support",
- "timedata",
- "unit_test",
- "unused",
- "use_requirements",
- "using",
- "wrapper",
- "wrong_project",
- "exit_status",
- ]
+# "default_toolset",
+ "dependency_property",
+ "dependency_test",
+ "direct_request_test",
+ "disambiguation",
+ "dll_path",
+ "double_loading",
+ "duplicate",
+ "example_libraries",
+ "example_make",
+ "exit_status",
+ "expansion",
+ "explicit",
+ "free_features_request",
+ "generator_selection",
+ "generators_test",
+ "implicit_dependency",
+ "indirect_conditional",
+ "inherit_toolset",
+ "inherited_dependency",
+ "inline",
+ "lib_source_property",
+ "library_chain",
+ "library_property",
+ "load_order",
+ "loop",
+ "make_rule",
+ "message",
+ "ndebug",
+ "no_type",
+ "notfile",
+ "ordered_include",
+ "out_of_tree",
+ "path_features",
+ "prebuilt",
+ "print",
+ "project_dependencies",
+ "project_glob",
+ "project_id",
+ "project_root_constants",
+ "project_root_rule",
+ "project_test3",
+ "project_test4",
+ "property_expansion",
+ "rebuilds",
+ "regression",
+ "relative_sources",
+ "remove_requirement",
+ "rescan_header",
+ "resolution",
+ "scanner_causing_rebuilds",
+ "searched_lib",
+ "skipping",
+ "sort_rule",
+ "source_locations",
+ "space_in_path",
+ "stage",
+ "standalone",
+ "static_and_shared_library",
+ "suffix",
+ "tag",
+ "test_result_dumping",
+ "test_rc",
+ "testing_support",
+ "timedata",
+ "unit_test",
+ "unused",
+ "use_requirements",
+ "using",
+ "wrapper",
+ "wrong_project",
+ "zlib"
+ ]
 
-if os.name == 'posix':
+if os.name == "posix":
     tests.append("symlink")
- # On windows, library order is not important, so skip this test. Besides, it
- # fails ;-). Further, the test relies on the fact that on Linux, one can
+ # On Windows, library order is not important, so skip this test. Besides,
+ # it fails ;-). Further, the test relies on the fact that on Linux, one can
     # build a shared library with unresolved symbols. This is not true on
- # Windows (even with cygwin gcc).
- if string.find(os.uname()[0], "CYGWIN") == -1:
+ # Windows, even with cygwin gcc.
+ if "CYGWIN" not in os.uname()[0]:
         tests.append("library_order")
 
-if string.find(BoostBuild.get_toolset(), 'gcc') == 0:
+if toolset.startswith("gcc"):
     tests.append("gcc_runtime")
 
-if ( string.find(BoostBuild.get_toolset(), 'gcc') == 0 )or \
- ( string.find(BoostBuild.get_toolset(), 'msvc') == 0 ):
+if toolset.startswith("gcc") or toolset.startswith("msvc"):
     tests.append("pch")
 
 if "--extras" in sys.argv:
@@ -249,8 +294,7 @@
     tests.append("example_customization")
     # Requires gettext tools.
     tests.append("example_gettext")
-
 elif not xml:
- print 'Note: skipping extra tests'
+ print("Note: skipping extra tests")
 
 run_tests(critical_tests, tests)

Copied: branches/release/tools/build/v2/test/test_rc.py (from r79148, /trunk/tools/build/v2/test/test_rc.py)
==============================================================================
--- /trunk/tools/build/v2/test/test_rc.py (original)
+++ branches/release/tools/build/v2/test/test_rc.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 
 # Copyright 2012 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Tests rc toolset behaviour.
 
@@ -16,8 +17,63 @@
     to be considered old and force all of its dependents to rebuild.
 
     """
- t = BoostBuild.Tester("-d1", pass_d0=False)
+ toolsetName = "__myDummyResourceCompilerToolset__"
 
+ # Used options rationale:
+ #
+ # -d4 & --debug-configuration
+ # Display additional information in case of test failure. In the past
+ # we have had testing system issues causing this test to fail
+ # sporadically for which -d+3 output had been instrumental in getting to
+ # the root cause (a touched file's timestamp was not as new as it should
+ # have been).
+ #
+ # --ignore-site-config --user-config=
+ # Disable reading any external Boost Build configuration. This test is
+ # self sufficient so these options protect it from being adversly
+ # affected by any local (mis)configuration..
+ t = BoostBuild.Tester(["-d4", "--debug-configuration",
+ "--ignore-site-config", "--user-config=", "toolset=%s" % toolsetName],
+ pass_d0=False, pass_toolset=False, use_test_config=False,
+ translate_suffixes=False)
+
+ # Prepare a dummy toolset so we do not get errors in case the default one
+ # is not found and that we can test rc.jam functionality without having to
+ # depend on the externally specified toolset actually supporting it exactly
+ # the way it is required for this test, e.g. gcc toolset, under some
+ # circumstances, uses a quiet action for generating its null RC targets.
+ t.write(toolsetName + ".jam", """\
+import feature ;
+import rc ;
+import type ;
+local toolset-name = "%s" ;
+feature.extend toolset : $(toolset-name) ;
+rule init ( ) { }
+rc.configure dummy-rc-command : <toolset>$(toolset-name) : <rc-type>dummy ;
+module rc
+{
+ rule compile.resource.dummy ( targets * : sources * : properties * )
+ {
+ import common ;
+ .TOUCH on $(targets) = [ common.file-touch-command ] ;
+ }
+ actions compile.resource.dummy { $(.TOUCH) "$(<)" }
+}
+# Make OBJ files generated by our toolset use the "obj" suffix on all
+# platforms. We need to do this explicitly for <target-os> windows & cygwin to
+# override the default OBJ type configuration (otherwise we would get
+# 'ambiguous key' errors on those platforms).
+local rule set-generated-obj-suffix ( target-os ? )
+{
+ type.set-generated-target-suffix OBJ : <toolset>$(toolset-name)
+ <target-os>$(target-os) : obj ;
+}
+set-generated-obj-suffix ;
+set-generated-obj-suffix windows ;
+set-generated-obj-suffix cygwin ;
+""" % toolsetName)
+
+ # Prepare project source files.
     t.write("jamroot.jam", """\
 ECHO {{{ [ modules.peek : XXX ] [ modules.peek : NOEXEC ] }}} ;
 obj xxx : xxx.rc ;
@@ -25,17 +81,17 @@
     t.write("xxx.rc", '1 MESSAGETABLE "xxx.bin"\n')
     t.write("xxx.bin", "foo")
 
- output_line = "*%s*" % t.adjust_suffix("xxx_res.obj")
-
     def test1(n, expect, noexec=False):
- params = "-sXXX=%d" % n
+ params = ["-sXXX=%d" % n]
         if noexec:
- params += " -n -sNOEXEC=NOEXEC"
+ params.append("-n")
+ params.append("-sNOEXEC=NOEXEC")
         t.run_build_system(params)
- t.expect_output_line("*NOEXEC*", noexec)
- t.expect_output_line(output_line, expect)
+ t.expect_output_lines("*NOEXEC*", noexec)
+ obj_file = "xxx_res.obj"
+ t.expect_output_lines("compile.resource.dummy *%s" % obj_file, expect)
         if expect and not noexec:
- expect("bin/$toolset/debug/xxx_res.obj")
+ expect("bin/%s/debug/%s" % (toolsetName, obj_file))
         t.expect_nothing_more()
 
     def test(n, expect):

Modified: branches/release/tools/build/v2/test/test_result_dumping.py
==============================================================================
--- branches/release/tools/build/v2/test/test_result_dumping.py (original)
+++ branches/release/tools/build/v2/test/test_result_dumping.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,32 +2,32 @@
 
 # Copyright 2008 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Tests dumping Boost Build based testing results.
 
 import BoostBuild
 
 
-################################################################################
+###############################################################################
 #
 # Test that dumping Boost Build based testing results works in case test code
 # is not located in a folder under the Jamroot folder.
 #
-################################################################################
+###############################################################################
 
-t = BoostBuild.Tester("--dump-tests")
+t = BoostBuild.Tester(["--dump-tests"], use_test_config=False)
 
-t.write("TestBuild/jamroot.jam", """
+t.write("TestBuild/jamroot.jam", """\
 import testing ;
 test-suite testit : [ run ../TestSource/test.cpp ] ;
 """)
 
-t.write("TestSource/test.cpp", """
-int main() {}
-""")
+t.write("TestSource/test.cpp", "int main() {}\n")
 
-t.run_build_system("", subdir="TestBuild")
-t.expect_output_line('boost-test(RUN) "*/TestBuild/test" : "../TestSource/test.cpp"')
+t.run_build_system(subdir="TestBuild")
+t.expect_output_lines('boost-test(RUN) "*/TestBuild/test" : '
+ '"../TestSource/test.cpp"')
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/testing_support.py
==============================================================================
--- branches/release/tools/build/v2/test/testing_support.py (original)
+++ branches/release/tools/build/v2/test/testing_support.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -21,7 +21,7 @@
     testing files with spaces in their name.
     """
 
- t = BoostBuild.Tester()
+ t = BoostBuild.Tester(use_test_config=False)
 
     t.write("valid source.cpp", "int main() {}\n");
 

Modified: branches/release/tools/build/v2/test/timedata.py
==============================================================================
--- branches/release/tools/build/v2/test/timedata.py (original)
+++ branches/release/tools/build/v2/test/timedata.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,30 +1,45 @@
 #!/usr/bin/python
 
 # Copyright 2005 David Abrahams
-# Copyright 2008 Jurko Gospodnetic
+# Copyright 2008, 2012 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Tests the build step timing facilities.
 
+# TODO: Missing tests:
+# 1. 'time' target with a source target representing more than one virtual
+# target. This happens in practice, e.g. when using the time rule on a msvc
+# exe target whose generator actually constructs an EXE and a PDB target.
+# When this is done - only the main virtual target's constructing action
+# should be timed.
+# 2. 'time' target with a source target representing a virtual target that
+# actually gets built by multiple actions run in sequence. In that case a
+# separate timing result should be reported for each of those actions. This
+# happens in practice, e.g. when using the time rule on a msvc exe target
+# which first gets created as a result of some link action and then its
+# manifest gets embedded inside it as a resource using a separate action
+# (assuming an appropriate property has been set for this target - see the
+# msvc module for details).
 
 import BoostBuild
 import re
 
 
-################################################################################
+###############################################################################
 #
 # basic_jam_action_test()
 # -----------------------
 #
-################################################################################
+###############################################################################
 
 def basic_jam_action_test():
     """Tests basic Jam action timing support."""
 
     t = BoostBuild.Tester(pass_toolset=0)
 
- t.write("file.jam", """
+ t.write("file.jam", """\
 rule time
 {
     DEPENDS $(<) : $(>) ;
@@ -58,9 +73,10 @@
 make bar : baz ;
 """)
 
- t.write("baz", "nothing\n")
+ t.write("baz", "nothing")
 
- expected_output = """\.\.\.found 4 targets\.\.\.
+ expected_output = """\
+\.\.\.found 4 targets\.\.\.
 \.\.\.updating 2 targets\.\.\.
 make bar
 time foo
@@ -68,8 +84,8 @@
 \.\.\.updated 2 targets\.\.\.$
 """
 
- t.run_build_system("-ffile.jam -d+1", stdout=expected_output, match=lambda
- actual, expected: re.search(expected, actual, re.DOTALL))
+ t.run_build_system(["-ffile.jam", "-d+1"], stdout=expected_output,
+ match=lambda actual, expected: re.search(expected, actual, re.DOTALL))
     t.expect_addition("foo")
     t.expect_addition("bar")
     t.expect_nothing_more()
@@ -77,23 +93,24 @@
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # boost_build_testing_support_timing_rule():
 # ------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def boost_build_testing_support_timing_rule():
- """Tests the target build timing rule provided by the Boost Build testing
- support system.
     """
+ Tests the target build timing rule provided by the Boost Build testing
+ support system.
 
- t = BoostBuild.Tester()
+ """
+ t = BoostBuild.Tester(use_test_config=False)
 
     t.write("aaa.cpp", "int main() {}\n")
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 import testing ;
 exe my-exe : aaa.cpp ;
 time my-time : my-exe ;
@@ -104,29 +121,32 @@
     t.expect_addition("bin/$toolset/debug/my-exe.exe")
     t.expect_addition("bin/$toolset/debug/my-time.time")
 
- t.expect_content_line("bin/$toolset/debug/my-time.time", "user: *")
- t.expect_content_line("bin/$toolset/debug/my-time.time", "system: *")
+ t.expect_content_lines("bin/$toolset/debug/my-time.time",
+ "user: *[0-9] seconds")
+ t.expect_content_lines("bin/$toolset/debug/my-time.time",
+ "system: *[0-9] seconds")
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # boost_build_testing_support_timing_rule_with_spaces_in_names()
 # --------------------------------------------------------------
 #
-################################################################################
+###############################################################################
 
 def boost_build_testing_support_timing_rule_with_spaces_in_names():
- """Tests the target build timing rule provided by the Boost Build testing
- support system when used with targets contining spaces in their names.
     """
+ Tests the target build timing rule provided by the Boost Build testing
+ support system when used with targets contining spaces in their names.
 
- t = BoostBuild.Tester()
+ """
+ t = BoostBuild.Tester(use_test_config=False)
 
     t.write("aaa bbb.cpp", "int main() {}\n")
 
- t.write("jamroot.jam", """
+ t.write("jamroot.jam", """\
 import testing ;
 exe "my exe" : "aaa bbb.cpp" ;
 time "my time" : "my exe" ;
@@ -137,18 +157,18 @@
     t.expect_addition("bin/$toolset/debug/my exe.exe")
     t.expect_addition("bin/$toolset/debug/my time.time")
 
- t.expect_content_line("bin/$toolset/debug/my time.time", "user: *")
- t.expect_content_line("bin/$toolset/debug/my time.time", "system: *")
+ t.expect_content_lines("bin/$toolset/debug/my time.time", "user: *")
+ t.expect_content_lines("bin/$toolset/debug/my time.time", "system: *")
 
     t.cleanup()
 
 
-################################################################################
+###############################################################################
 #
 # main()
 # ------
 #
-################################################################################
+###############################################################################
 
 basic_jam_action_test()
 boost_build_testing_support_timing_rule()

Modified: branches/release/tools/build/v2/test/tree.py
==============================================================================
--- branches/release/tools/build/v2/test/tree.py (original)
+++ branches/release/tools/build/v2/test/tree.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,14 +1,90 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2001, 2002 Vladimir Prus
+# Copyright 2012 Jurko Gospodnetic
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
-# This file is based in part on the content of svn_tree.py.
+###############################################################################
+#
+# Based in part on an old Subversion tree.py source file (tools for comparing
+# directory trees). See http://subversion.tigris.org for more information.
+#
+# Copyright (c) 2001 Sam Tobin-Hochstadt. All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which you should
+# have received as part of this distribution. The terms are also available at
+# http://subversion.tigris.org/license-1.html. If newer versions of this
+# license are posted there, you may use a newer version instead, at your
+# option.
+#
+###############################################################################
+
+import os
+import os.path
+import stat
+import sys
+
+
+class TreeNode:
+ """
+ Fundamental data type used to build file system tree structures.
+
+ If CHILDREN is None, then the node represents a file. Otherwise, CHILDREN
+ is a list of the nodes representing that directory's children.
+
+ NAME is simply the name of the file or directory. CONTENTS is a string
+ holding the file's contents (if a file).
+
+ """
+
+ def __init__(self, name, children=None, contents=None):
+ assert children is None or contents is None
+ self.name = name
+ self.mtime = 0
+ self.children = children
+ self.contents = contents
+ self.path = name
+
+ def add_child(self, newchild):
+ assert not self.is_file()
+ for a in self.children:
+ if a.name == newchild.name:
+ if newchild.is_file():
+ a.contents = newchild.contents
+ a.path = os.path.join(self.path, newchild.name)
+ else:
+ for i in newchild.children:
+ a.add_child(i)
+ break
+ else:
+ self.children.append(newchild)
+ newchild.path = os.path.join(self.path, newchild.name)
 
-import svn_tree;
+ def get_child(self, name):
+ """
+ If the given TreeNode directory NODE contains a child named NAME,
+ return the child; else, return None.
+
+ """
+ for n in self.children:
+ if n.name == name:
+ return n
+
+ def is_file(self):
+ return self.children is None
+
+ def pprint(self):
+ print(" * Node name: %s" % self.name)
+ print(" Path: %s" % self.path)
+ print(" Contents: %s" % self.contents)
+ if self.is_file():
+ print(" Children: is a file.")
+ else:
+ print(" Children: %d" % len(self.children))
 
-class Trees_difference:
 
+class TreeDifference:
     def __init__(self):
         self.added_files = []
         self.removed_files = []
@@ -22,99 +98,146 @@
         self.touched_files.extend(other.touched_files)
 
     def ignore_directories(self):
- "Removes directories for list of found differences"
-
- def not_dir(x):
- return x[-1] != "/"
+ """Removes directories from our lists of found differences."""
+ not_dir = lambda x : x[-1] != "/"
         self.added_files = filter(not_dir, self.added_files)
         self.removed_files = filter(not_dir, self.removed_files)
         self.modified_files = filter(not_dir, self.modified_files)
         self.touched_files = filter(not_dir, self.touched_files)
 
- def pprint(self, f=None):
- print >> f, "Added files :", self.added_files
- print >> f, "Removed files :", self.removed_files
- print >> f, "Modified files:", self.modified_files
- print >> f, "Touched files :", self.touched_files
+ def pprint(self, file=sys.stdout):
+ file.write("Added files : %s\n" % self.added_files)
+ file.write("Removed files : %s\n" % self.removed_files)
+ file.write("Modified files: %s\n" % self.modified_files)
+ file.write("Touched files : %s\n" % self.touched_files)
 
     def empty(self):
- return ( len(self.added_files) == 0 ) and \
- ( len(self.removed_files) == 0 ) and \
- ( len(self.modified_files) == 0 ) and \
- ( len(self.touched_files) == 0 )
+ return not (self.added_files or self.removed_files or
+ self.modified_files or self.touched_files)
 
-def build_tree(dir):
- return svn_tree.build_tree_from_wc(dir, load_props=0, ignore_svn=1)
 
-def trees_difference(a, b, current_name=""):
- """Compare SVNTreeNodes A and B, and create Trees_difference class."""
+def build_tree(path):
+ """
+ Takes PATH as the folder path, walks the file system below that path, and
+ creates a tree structure based on any files and folders found there.
+ Returns the prepared tree structure plus the maximum file modification
+ timestamp under the given folder.
 
- assert a.name == b.name
+ """
+ return _handle_dir(os.path.normpath(path))
+
+
+def tree_difference(a, b):
+ """Compare TreeNodes A and B, and create a TreeDifference instance."""
+ return _do_tree_difference(a, b, "", True)
 
- result = Trees_difference()
- try:
- # A and B are both files.
- if ((a.children is None) and (b.children is None)):
- assert a.name == b.name
- if svn_tree.compare_file_nodes(a, b):
- result.modified_files.append(current_name)
- elif (a.mtime != b.mtime):
- result.touched_files.append(current_name)
-
- # One is a file, one is a directory.
- # this case is disabled because svn_tree doesn't distinguish
- # empty directories from files, at least on Cygwin.
- elif 0 and (((a.children is None) and (b.children is not None))
- or ((a.children is not None) and (b.children is None))):
- a.pprint()
- b.pprint()
- raise svn_tree.SVNTypeMismatch
- # They're both directories.
- else:
- # accounted_for holds childrens present in both trees
- accounted_for = []
- for a_child in (a.children or []):
- b_child = svn_tree.get_child(b, a_child.name)
- if b_child:
- accounted_for.append(b_child)
- if current_name:
- result.append(trees_difference(a_child, b_child, current_name + "/" + a_child.name))
- else:
- result.append(trees_difference(a_child, b_child, a_child.name))
- else:
- if current_name:
- result.removed_files.append(current_name + "/" + a_child.name)
- else:
- result.removed_files.append(a_child.name)
- for b_child in (b.children or []):
- if (b_child not in accounted_for):
- result.added_files.extend(traverse_tree(b_child, current_name))
-
- except svn_tree.SVNTypeMismatch:
- print 'Unequal Types: one Node is a file, the other is a directory'
- raise svn_tree.SVNTreeUnequal
- except svn_tree.SVNTreeIsNotDirectory:
- print "Error: Foolish call to get_child."
- sys.exit(1)
- except IndexError:
- print "Error: unequal number of children"
- raise svn_tree.SVNTreeUnequal
- return result
 
-def dump_tree(t):
- svn_tree.dump_tree(t)
+def _do_tree_difference(a, b, parent_path, root=False):
+ """Internal recursive worker function for tree_difference()."""
 
-def traverse_tree(t, parent_name=""):
- """ Returns the list of all names in tree. """
- if parent_name:
- full_node_name = parent_name + "/" + t.name
+ # We do not want to list root node names.
+ if root:
+ assert not parent_path
+ assert not a.is_file()
+ assert not b.is_file()
+ full_path = ""
     else:
- full_node_name = t.name
+ assert a.name == b.name
+ full_path = parent_path + a.name
+ result = TreeDifference()
+
+ # A and B are both files.
+ if a.is_file() and b.is_file():
+ if a.contents != b.contents:
+ result.modified_files.append(full_path)
+ elif a.mtime != b.mtime:
+ result.touched_files.append(full_path)
+ return result
+
+ # Directory converted to file.
+ if not a.is_file() and b.is_file():
+ result.removed_files.extend(_traverse_tree(a, parent_path))
+ result.added_files.append(full_path)
+
+ # File converted to directory.
+ elif a.is_file() and not b.is_file():
+ result.removed_files.append(full_path)
+ result.added_files.extend(_traverse_tree(b, parent_path))
 
- if (t.children is None):
+ # A and B are both directories.
+ else:
+ if full_path:
+ full_path += "/"
+ accounted_for = [] # Children present in both trees.
+ for a_child in a.children:
+ b_child = b.get_child(a_child.name)
+ if b_child:
+ accounted_for.append(b_child)
+ result.append(_do_tree_difference(a_child, b_child, full_path))
+ else:
+ result.removed_files.append(full_path + a_child.name)
+ for b_child in b.children:
+ if b_child not in accounted_for:
+ result.added_files.extend(_traverse_tree(b_child, full_path))
+
+ return result
+
+
+def _traverse_tree(t, parent_path):
+ """Returns a list of all names in a tree."""
+ assert not parent_path or parent_path[-1] == "/"
+ full_node_name = parent_path + t.name
+ if t.is_file():
         result = [full_node_name]
     else:
- result = [full_node_name + "/"]
+ name_prefix = full_node_name + "/"
+ result = [name_prefix]
         for i in t.children:
- result.extend(traverse_tree(i, full_node_name))
+ result.extend(_traverse_tree(i, name_prefix))
     return result
+
+
+def _get_text(path):
+ """Return a string with the textual contents of a file at PATH."""
+ fp = open(path, 'r')
+ try:
+ return fp.read()
+ finally:
+ fp.close()
+
+
+def _handle_dir(path):
+ """
+ Main recursive worker function for build_tree(). Returns a newly created
+ tree node representing the given normalized folder path as well as the
+ maximum file/folder modification time detected under the same path.
+
+ """
+ files = []
+ dirs = []
+ node = TreeNode(os.path.basename(path), children=[])
+ max_mtime = node.mtime = os.stat(path).st_mtime
+
+ # List files & folders.
+ for f in os.listdir(path):
+ f = os.path.join(path, f)
+ if os.path.isdir(f):
+ dirs.append(f)
+ elif os.path.isfile(f):
+ files.append(f)
+
+ # Add a child node for each file.
+ for f in files:
+ fcontents = _get_text(f)
+ new_file_node = TreeNode(os.path.basename(f), contents=fcontents)
+ new_file_node.mtime = os.stat(f).st_mtime
+ max_mtime = max(max_mtime, new_file_node.mtime)
+ node.add_child(new_file_node)
+
+ # For each subdir, create a node, walk its tree, add it as a child.
+ for d in dirs:
+ new_dir_node, new_max_mtime = _handle_dir(d)
+ max_mtime = max(max_mtime, new_max_mtime)
+ node.add_child(new_dir_node)
+
+ return node, max_mtime

Modified: branches/release/tools/build/v2/test/unit_test.py
==============================================================================
--- branches/release/tools/build/v2/test/unit_test.py (original)
+++ branches/release/tools/build/v2/test/unit_test.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,7 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 # Create the needed files.
 t.write("jamroot.jam", """
@@ -30,7 +30,7 @@
 helper() {}
 """)
 
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("bin/$toolset/debug/link-static/test.passed")
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/unit_tests.py
==============================================================================
--- branches/release/tools/build/v2/test/unit_tests.py (original)
+++ branches/release/tools/build/v2/test/unit_tests.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,13 +1,11 @@
 #!/usr/bin/python
 
-# Copyright 2002, 2003 Vladimir Prus
-# 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)
+# Copyright 2002, 2003 Vladimir Prus
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import BoostBuild
 
 t = BoostBuild.Tester(pass_toolset=0)
-
-t.run_build_system(extra_args="--debug --build-system=test/test")
-
+t.run_build_system(["--debug", "--build-system=test/test"])
 t.cleanup()

Modified: branches/release/tools/build/v2/test/unused.py
==============================================================================
--- branches/release/tools/build/v2/test/unused.py (original)
+++ branches/release/tools/build/v2/test/unused.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,33 +1,81 @@
 #!/usr/bin/python
 
-# Copyright 2003 Vladimir Prus
-# 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)
+# Copyright 2003 Vladimir Prus
+# 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)
 
 # Test that unused sources are at least reported.
 
 import BoostBuild
-from string import find
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(["-d+2"], use_test_config=False)
 
-t.set_tree("unused")
+t.write("a.cpp", "int main() {}\n")
+t.write("b.cpp", "\n")
+t.write("b.x", "")
+t.write("jamroot.jam", """\
+import "class" : new ;
+import modules ;
+import project ;
+import targets ;
+import type ;
+import virtual-target ;
+
+type.register X : x ;
+
+class test-target-class : basic-target
+{
+ rule construct ( name : source-targets * : property-set )
+ {
+ local result = [ property-set.empty ] ;
+ if ! [ modules.peek : GENERATE_NOTHING ]
+ {
+ result += [ virtual-target.from-file b.x : . : $(self.project) ] ;
+ if ! [ modules.peek : GENERATE_ONLY_UNUSABLE ]
+ {
+ result += [ virtual-target.from-file b.cpp : . : $(self.project)
+ ] ;
+ }
+ }
+ return $(result) ;
+ }
+
+ rule compute-usage-requirements ( rproperties : targets * )
+ {
+ return [ property-set.create <define>FOO ] ;
+ }
+}
+
+rule make-b-main-target
+{
+ local project = [ project.current ] ;
+ targets.main-target-alternative [ new test-target-class b : $(project) ] ;
+}
+
+exe a : a.cpp b c ;
+make-b-main-target ;
+alias c ; # Expands to nothing, intentionally.
+""")
 
 t.run_build_system()
+
 # The second invocation should do nothing, and produce no warning. The previous
 # invocation might have printed executed actions and other things, so it is not
-# easy to check if warning was issued or not.
+# easy to check if a warning was issued or not.
 t.run_build_system(stdout="")
 
-t.run_build_system("-sGENERATE_ONLY_UNUSABLE=1", stdout="")
+t.run_build_system(["-sGENERATE_ONLY_UNUSABLE=1"], stdout="")
 
-# Now check that even if main target generates nothing, its usage requirements
-# are still propagated to dependants.
-t.write("a.cpp", """
-#ifdef FOO
-int main() {}
+# Check that even if main target generates nothing, its usage requirements are
+# still propagated to dependants.
+t.write("a.cpp", """\
+#ifndef FOO
+ #error We refuse to compile without FOO being defined!
+ We_refuse_to_compile_without_FOO_being_defined
 #endif
+int main() {}
 """)
-t.run_build_system("-sGENERATE_NOTHING=1")
+t.run_build_system(["-sGENERATE_NOTHING=1"])
 
 t.cleanup()

Modified: branches/release/tools/build/v2/test/use_requirements.py
==============================================================================
--- branches/release/tools/build/v2/test/use_requirements.py (original)
+++ branches/release/tools/build/v2/test/use_requirements.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,39 +7,39 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 
-# Test that use requirements on main target work (and a propagated all the way
-# up, not only to direct dependants).
-t.write("jamroot.jam", "import gcc ;")
+# Test that usage requirements on main targets work (and are propagated all the
+# way up, and not only to direct dependants).
+t.write("jamroot.jam", "")
 
 # Note: 'lib cc ..', not 'lib c'. If using 'lib c: ...' the HP-CXX linker will
 # confuse it with the system C runtime.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 lib b : b.cpp : <link>shared:<define>SHARED_B : :
     <define>FOO <link>shared:<define>SHARED_B ;
 lib cc : c.cpp b ;
 exe a : a.cpp cc ;
 """)
 
-t.write("b.cpp", """
+t.write("b.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_B)
 __declspec(dllexport)
 #endif
-foo() {}\n
+foo() {}
 """)
 
-t.write("c.cpp", """
+t.write("c.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_B)
 __declspec(dllexport)
 #endif
-create_lib_please() {}\n
+create_lib_please() {}
 """)
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 #ifdef FOO
 void
 # if defined(_WIN32) && defined(SHARED_B)
@@ -51,20 +51,19 @@
 """)
 
 t.run_build_system()
-t.run_build_system("--clean")
+t.run_build_system(["--clean"])
 
 
 # Test that use requirements on main target work, when they are referred using
 # 'dependency' features.
-t.write("jamroot.jam", "import gcc ;")
 
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 lib b : b.cpp : <link>shared:<define>SHARED_B : : <define>FOO
     <link>shared:<define>SHARED_B ;
 exe a : a.cpp : <use>b ;
 """)
 
-t.write("b.cpp", """
+t.write("b.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_B)
 __declspec(dllexport)
@@ -72,33 +71,32 @@
 foo() {}
 """)
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 #ifdef FOO
 int main() {}
 #endif
 """)
 
 t.run_build_system()
-
-t.run_build_system("--clean")
+t.run_build_system(["--clean"])
 
 
 # Test that usage requirements on a project work.
 t.write("jamfile.jam", "exe a : a.cpp lib//b ;")
 
-t.write("lib/jamfile.jam", """
+t.write("lib/jamfile.jam", """\
 project
    : requirements <link>shared:<define>SHARED_B
    : usage-requirements <define>FOO <link>shared:<define>SHARED_B ;
 lib b : b.cpp ;
 """)
 
-t.write("lib/b.cpp", """
+t.write("lib/b.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_B)
 __declspec(dllexport)
 #endif
-foo() {}\n
+foo() {}
 """)
 
 t.run_build_system()
@@ -107,39 +105,39 @@
 # Test that use requirements are inherited correctly.
 t.write("jamfile.jam", "exe a : a.cpp lib/1//b ;")
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 #if defined(FOO) && defined(ZOO)
 void foo() {}
 #endif
 int main() { foo(); }
 """)
 
-t.write("lib/jamfile.jam", """
+t.write("lib/jamfile.jam", """\
 project : requirements : usage-requirements <define>FOO ;
 """)
 
-t.write("lib/1/jamfile.jam", """
+t.write("lib/1/jamfile.jam", """\
 project
    : requirements <link>shared:<define>SHARED_B
    : usage-requirements <define>ZOO <link>shared:<define>SHARED_B ;
 lib b : b.cpp ;
 """)
 
-t.write("lib/1/b.cpp", """
+t.write("lib/1/b.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_B)
 __declspec(dllexport)
 #endif
-foo() {}\n
+foo() {}
 """)
 
 t.run_build_system()
-t.run_build_system("--clean")
+t.run_build_system(["--clean"])
 
 
-# Test that we correctly handle dependency features in use requirements on
+# Test that we correctly handle dependency features in usage requirements on
 # target.
-t.write("jamfile.jam", """
+t.write("jamfile.jam", """\
 lib b : b.cpp : <link>shared:<define>SHARED_B : : <define>FOO
     <link>shared:<define>SHARED_B ;
 
@@ -151,7 +149,7 @@
 exe a : a.cpp cc ;
 """)
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 #ifdef FOO
 void
 # if defined(_WIN32) && defined(SHARED_B)
@@ -163,7 +161,7 @@
 int main() { foo(); }
 """)
 
-t.write("c.cpp", """
+t.write("c.cpp", """\
 int
 #if defined(_WIN32) && defined(SHARED_C)
 __declspec(dllexport)
@@ -172,22 +170,20 @@
 """)
 
 t.run_build_system()
-t.run_build_system("--clean")
+t.run_build_system(["--clean"])
 
 
 # Test correct handling of dependency features in project requirements.
-t.write("jamfile.jam", """
-exe a : a.cpp lib1//cc ;
-""")
+t.write("jamfile.jam", "exe a : a.cpp lib1//cc ;")
 
-t.write("lib1/jamfile.jam", """
+t.write("lib1/jamfile.jam", """\
 project
     : requirements <link>shared:<define>SHARED_C
     : usage-requirements <library>../lib2//b <link>shared:<define>SHARED_C ;
 lib cc : c.cpp ;
 """)
 
-t.write("lib1/c.cpp", """
+t.write("lib1/c.cpp", """\
 int
 #if defined(_WIN32) && defined(SHARED_C)
 __declspec(dllexport)
@@ -195,7 +191,7 @@
 must_export_something;
 """)
 
-t.write("lib2/jamfile.jam", """
+t.write("lib2/jamfile.jam", """\
 lib b : b.cpp : <link>shared:<define>SHARED_B : : <define>FOO
     <link>shared:<define>SHARED_B ;
 """)
@@ -205,16 +201,17 @@
 t.run_build_system()
 
 
-# Test that dependency feature in use requirements are built with the correct
-# properties.
+# Test that targets listed in dependency features in usage requirements are
+# built with the correct properties.
 t.rm(".")
 
-t.write("jamfile.jam", """
+t.write("jamroot.jam", "")
+t.write("jamfile.jam", """\
 lib main : main.cpp : <use>libs//lib1 : : <library>libs//lib1 ;
 exe hello : hello.cpp main : ;
 """)
 
-t.write("main.cpp", """
+t.write("main.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_LIB1)
 __declspec(dllimport)
@@ -225,12 +222,7 @@
 """)
 
 t.write("hello.cpp", "\n")
-
-t.write("jamroot.jam", """
-import gcc ;
-""")
-
-t.write("libs/a.cpp", """
+t.write("libs/a.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_LIB1)
 __declspec(dllexport)
@@ -239,17 +231,17 @@
 """)
 
 
-# This library should be build with the same properties as 'main'. This is a
+# This library should be built with the same properties as 'main'. This is a
 # regression test for a bug when they were generated with empty properties, and
-# there were ambiguity between variants.
-t.write("libs/jamfile.jam", """
+# there were ambiguities between variants.
+t.write("libs/jamfile.jam", """\
 lib lib1 : a_d.cpp : <variant>debug <link>shared:<define>SHARED_LIB1 : :
     <link>shared:<define>SHARED_LIB1 ;
 lib lib1 : a.cpp : <variant>release <link>shared:<define>SHARED_LIB1 : :
     <link>shared:<define>SHARED_LIB1 ;
 """)
 
-t.write("libs/a_d.cpp", """
+t.write("libs/a_d.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_LIB1)
 __declspec(dllexport)
@@ -257,36 +249,32 @@
 foo() {}
 """)
 
-t.run_build_system("link=static")
+t.run_build_system(["link=static"])
 t.expect_addition("libs/bin/$toolset/debug/link-static/a_d.obj")
 
 
 # Test that indirect conditionals are respected in usage requirements.
 t.rm(".")
 
-t.write("jamroot.jam", """
-rule has-foo ( properties * )
-{
- return <define>HAS_FOO ;
-}
-
+t.write("jamroot.jam", """\
+rule has-foo ( properties * ) { return <define>HAS_FOO ; }
 exe a : a.cpp b ;
 lib b : b.cpp : <link>static : : <conditional>@has-foo ;
 """)
 
-t.write("a.cpp", """
+t.write("a.cpp", """\
 #ifdef HAS_FOO
 void foo();
 int main() { foo(); }
 #endif
 """)
 
-t.write("b.cpp", """
+t.write("b.cpp", """\
 void
 #if defined(_WIN32) && defined(SHARED_B)
 __declspec(dllexport)
 #endif
-foo() {}\n
+foo() {}
 """)
 
 t.run_build_system()

Modified: branches/release/tools/build/v2/test/using.py
==============================================================================
--- branches/release/tools/build/v2/test/using.py (original)
+++ branches/release/tools/build/v2/test/using.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -7,34 +7,24 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
-t.write("sub/a.cpp", """
-int main() {}
-""")
-
-t.write("jamroot.jam", """
-using some_tool ;
-""")
-
-t.write("some_tool.jam", """
+t.write("jamroot.jam", "using some_tool ;")
+t.write("some_tool.jam", """\
 import project ;
 project.initialize $(__name__) ;
 rule init ( ) { }
 """)
 
-t.write("some_tool.py", """
+t.write("some_tool.py", """\
 from b2.manager import get_manager
-
 get_manager().projects().initialize(__name__)
-
 def init():
     pass
 """)
 
-t.write("sub/jamfile.jam", """
-exe a : a.cpp ;
-""")
+t.write("sub/a.cpp", "int main() {}\n")
+t.write("sub/jamfile.jam", "exe a : a.cpp ;")
 
 t.run_build_system(subdir="sub")
 t.expect_addition("sub/bin/$toolset/debug/a.exe")

Modified: branches/release/tools/build/v2/test/wrapper.py
==============================================================================
--- branches/release/tools/build/v2/test/wrapper.py (original)
+++ branches/release/tools/build/v2/test/wrapper.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -10,7 +10,7 @@
 import BoostBuild
 
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("jamfile.jam", """
 my-test : test.cpp ;

Modified: branches/release/tools/build/v2/test/wrong_project.py
==============================================================================
--- branches/release/tools/build/v2/test/wrong_project.py (original)
+++ branches/release/tools/build/v2/test/wrong_project.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,8 +2,8 @@
 
 # Copyright Vladimir Prus 2005.
 # 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 accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Regression test. When Jamfile contained "using whatever ; " and the 'whatever'
 # module declared a project, then all targets in Jamfile were considered to be
@@ -11,26 +11,24 @@
 
 import BoostBuild
 
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(use_test_config=False)
 
 t.write("a.cpp", "int main() {}\n")
 
-t.write("jamroot.jam", """
+t.write("jamroot.jam", """\
 using some_tool ;
 exe a : a.cpp ;
 """)
 
-t.write("some_tool.jam", """
+t.write("some_tool.jam", """\
 import project ;
 project.initialize $(__name__) ;
 rule init ( ) { }
 """)
 
-t.write("some_tool.py", """
+t.write("some_tool.py", """\
 from b2.manager import get_manager
-
 get_manager().projects().initialize(__name__)
-
 def init():
     pass
 """)

Copied: branches/release/tools/build/v2/test/zlib.py (from r83773, /trunk/tools/build/v2/test/zlib.py)
==============================================================================
--- /trunk/tools/build/v2/test/zlib.py (original)
+++ branches/release/tools/build/v2/test/zlib.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,7 +8,7 @@
 import BoostBuild
 import MockToolset
 
-t = BoostBuild.Tester(arguments=['toolset=mock'], pass_toolset=0)
+t = BoostBuild.Tester(arguments=['toolset=mock', '--ignore-site-config', '--user-config='], pass_toolset=0)
 
 MockToolset.create(t)
 
@@ -30,8 +30,19 @@
 ''')
 
 t.run_build_system()
-t.expect_addition('bin/standalone/zlib/mock/debug/libz.so')
-t.expect_addition('bin/standalone/zlib/mock/debug/link-static/libz.a')
+t.expect_addition('bin/standalone/zlib/mock/debug/z.dll')
+t.expect_addition('bin/standalone/zlib/mock/debug/link-static/z.lib')
+
+t.rm('zlib')
+
+# Generic definitions that aren't configuration specific
+common_stuff = '''
+source_file('test.cpp', 'test.cpp')
+source_file('main.cpp', 'int main() {}')
+source_file('zlib.h.cpp', '#include <zlib.h>')
+action('-c -x c++ $main.cpp -o $main.o')
+'''
+t.write('test.cpp', 'test.cpp')
 
 # Default initialization - static library
 t.rm('bin')
@@ -41,21 +52,15 @@
 exe test : test.cpp /zlib//zlib : : <link>static <link>shared ;
 """)
 
-t.write('test.cpp', 'test.cpp')
-
-MockToolset.set_expected(t, '''
-source_file('test.cpp', 'test.cpp')
-source_file('main.cpp', 'int main() {}')
-source_file('zlib.h.cpp', '#include <zlib.h>')
-action('-c -x c++ $main.cpp -o $main.o')
+MockToolset.set_expected(t, common_stuff + '''
 action('$main.o --static-lib=z -o $config.exe')
 action('-c -x c++ $zlib.h.cpp -o $zlib.h.o')
 action('-c -x c++ $test.cpp -o $test.o')
 action('$test.o --static-lib=z -o $test')
 ''')
 t.run_build_system()
-t.expect_addition('bin/mock/debug/test')
-t.expect_addition('bin/mock/debug/link-static/test')
+t.expect_addition('bin/mock/debug/test.exe')
+t.expect_addition('bin/mock/debug/link-static/test.exe')
 
 # Default initialization - shared library
 t.rm('bin')
@@ -65,20 +70,50 @@
 exe test : test.cpp /zlib//zlib : : <link>static <link>shared ;
 """)
 
-t.write('test.cpp', 'test.cpp')
-
-MockToolset.set_expected(t, '''
-source_file('test.cpp', 'test.cpp')
-source_file('main.cpp', 'int main() {}')
-source_file('zlib.h.cpp', '#include <zlib.h>')
-action('-c -x c++ $main.cpp -o $main.o')
+MockToolset.set_expected(t, common_stuff + '''
 action('$main.o --shared-lib=z -o $config.exe')
 action('-c -x c++ $zlib.h.cpp -o $zlib.h.o')
 action('-c -x c++ $test.cpp -o $test.o')
 action('$test.o --shared-lib=z -o $test')
 ''')
 t.run_build_system()
-t.expect_addition('bin/mock/debug/test')
-t.expect_addition('bin/mock/debug/link-static/test')
+t.expect_addition('bin/mock/debug/test.exe')
+t.expect_addition('bin/mock/debug/link-static/test.exe')
+
+# Initialization in explicit location - static library
+t.rm('bin')
+t.write("Jamroot.jam", """
+path-constant here : . ;
+using zlib : : <name>myzlib <include>$(here)/zlib <search>$(here)/zlib ;
+exe test : test.cpp /zlib//zlib : : <link>static <link>shared ;
+""")
+
+t.write('zlib/zlib.h', 'zlib')
+
+MockToolset.set_expected(t, common_stuff + '''
+action('$main.o -L./zlib --static-lib=myzlib -o $config.exe')
+action('-c -x c++ $test.cpp -I./zlib -o $test.o')
+action('$test.o -L./zlib --static-lib=myzlib -o $test')
+''')
+t.run_build_system()
+t.expect_addition('bin/mock/debug/test.exe')
+t.expect_addition('bin/mock/debug/link-static/test.exe')
+
+# Initialization in explicit location - shared library
+t.rm('bin')
+t.write("Jamroot.jam", """
+path-constant here : . ;
+using zlib : : <name>myzlib <include>$(here)/zlib <search>$(here)/zlib ;
+exe test : test.cpp /zlib//zlib : : <link>static <link>shared ;
+""")
+
+MockToolset.set_expected(t, common_stuff + '''
+action('$main.o -L./zlib --shared-lib=myzlib -o $config.exe')
+action('-c -x c++ $test.cpp -I./zlib -o $test.o')
+action('$test.o -L./zlib --shared-lib=myzlib -o $test')
+''')
+t.run_build_system()
+t.expect_addition('bin/mock/debug/test.exe')
+t.expect_addition('bin/mock/debug/link-static/test.exe')
 
 t.cleanup()

Modified: branches/release/tools/build/v2/tools/auto-index.jam
==============================================================================
--- branches/release/tools/build/v2/tools/auto-index.jam (original)
+++ branches/release/tools/build/v2/tools/auto-index.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -157,15 +157,7 @@
         #ECHO "binary = " $(auto-index-binary) ;
         #ECHO "dependencies = " $(auto-index-binary-dependencies) ;
 
- if [ $(property-set).get <auto-index> ] = "on"
- {
- return [ generator.run $(project) $(name) : $(property-set) : $(sources) ] ;
- }
- else
- {
- return [ generators.construct $(project) $(name) : DOCBOOK : $(property-set)
- : $(sources) ] ;
- }
+ return [ generator.run $(project) $(name) : $(property-set) : $(sources) ] ;
     }
 }
 
@@ -192,7 +184,7 @@
 toolset.flags auto-index.auto-index AI-COMMAND <auto-index-binary> ;
 toolset.flags auto-index.auto-index AI-DEPENDENCIES <auto-index-binary-dependencies> ;
 
-generators.register [ class.new auto-index-generator auto-index.auto-index : DOCBOOK : DOCBOOK(%.auto_index) ] ;
+generators.register [ class.new auto-index-generator auto-index.auto-index : DOCBOOK : DOCBOOK(%.auto_index) : <auto-index>on ] ;
 generators.override auto-index.auto-index : boostbook.boostbook-to-docbook ;
 
 rule auto-index ( target : source : properties * )

Modified: branches/release/tools/build/v2/tools/boostbook.jam
==============================================================================
--- branches/release/tools/build/v2/tools/boostbook.jam (original)
+++ branches/release/tools/build/v2/tools/boostbook.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,18 +1,18 @@
-# Copyright 2003, 2004, 2005 Dave Abrahams
-# Copyright 2003, 2004, 2005 Douglas Gregor
-# Copyright 2005, 2006, 2007 Rene Rivera
-# Copyright 2003, 2004, 2005 Vladimir Prus
-# 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)
+# Copyright 2003, 2004, 2005 Dave Abrahams
+# Copyright 2003, 2004, 2005 Douglas Gregor
+# Copyright 2005, 2006, 2007 Rene Rivera
+# Copyright 2003, 2004, 2005 Vladimir Prus
+# 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)
 
-# This module defines rules to handle generation of documentation
-# from BoostBook sources.
+# This module defines rules to handle generation of documentation from BoostBook
+# sources.
 #
-# The type of output is controlled by the <format> feature which can
-# have the following values::
-#
-# * html: Generates html documention. This is the default.
-# * xhtml: Generates xhtml documentation
+# The type of output is controlled by the <format> feature which can have the
+# following values:
+# * html: Generates html documentation. This is the default.
+# * xhtml: Generates xhtml documentation.
 # * htmlhelp: Generates html help output.
 # * onehtml: Generates a single html page.
 # * man: Generates man pages.
@@ -22,42 +22,45 @@
 # * fo: Generates XSL formating objects.
 # * tests: Extracts test cases from the boostbook XML.
 #
-# format is an implicit feature, so typing pdf on the command
-# line (for example) is a short-cut for format=pdf.
+# <format> is an implicit feature, so for example, typing pdf on the command
+# line is a short-cut for format=pdf.
 
+import build-system ;
 import "class" : new ;
 import common ;
-import errors ;
-import targets ;
 import feature ;
 import generators ;
+import make ;
+import modules ;
+import os ;
+import path ;
 import print ;
-import property ;
 import project ;
+import property ;
 import property-set ;
 import regex ;
 import scanner ;
 import sequence ;
-import make ;
-import os ;
+import targets ;
 import type ;
-import modules path project ;
-import build-system ;
-
-import xsltproc : xslt xslt-dir ;
+import virtual-target ;
+import xsltproc ;
 
 # Make this module into a project.
 project.initialize $(__name__) ;
 project boostbook ;
 
+.debug-configuration = [ MATCH ^(--debug-configuration)$ : [ modules.peek : ARGV
+ ] ] ;
 
-feature.feature format : html xhtml htmlhelp onehtml man pdf ps docbook fo tests
- : incidental implicit composite propagated ;
+feature.feature format
+ : html xhtml htmlhelp onehtml man pdf ps docbook fo tests
+ : incidental implicit composite propagated ;
 
 type.register DTDXML : dtdxml ;
 type.register XML : xml ;
 type.register BOOSTBOOK : boostbook : XML ;
-type.register DOCBOOK : docbook : XML ;
+type.register DOCBOOK : docbook : XML ;
 type.register FO : fo : XML ;
 type.register PDF : pdf ;
 type.register PS : ps ;
@@ -67,391 +70,443 @@
 type.register HTMLHELP ;
 type.register MANPAGES ;
 type.register TESTS : tests ;
-# Artificial target type, used to require invocation of top-level
-# BoostBook generator.
-type.register BOOSTBOOK_MAIN ;
 
 
 # Initialize BoostBook support.
+#
 rule init (
- docbook-xsl-dir ? # The DocBook XSL stylesheet directory. If not
- # provided, we use DOCBOOK_XSL_DIR from the environment
- # (if available) or look in standard locations.
- # Otherwise, we let the XML processor load the
- # stylesheets remotely.
-
+ docbook-xsl-dir ? # The DocBook XSL stylesheet directory. If not provided,
+ # we use DOCBOOK_XSL_DIR from the environment (if
+ # available) or look in standard locations. Otherwise,
+ # we let the XML processor load the stylesheets
+ # remotely.
+
     : docbook-dtd-dir ? # The DocBook DTD directory. If not provided, we use
                         # DOCBOOK_DTD_DIR From the environment (if available) or
- # look in standard locations. Otherwise, we let the XML
+ # look in standard locations. Otherwise, we let the XML
                         # processor load the DTD remotely.
 
     : boostbook-dir ? # The BoostBook directory with the DTD and XSL subdirs.
 )
 {
+ if ! $(.initialized)
+ {
+ .initialized = true ;
 
- if ! $(.initialized)
- {
- .initialized = true ;
-
- check-boostbook-dir $(boostbook-dir) ;
- find-tools $(docbook-xsl-dir) : $(docbook-dtd-dir) : $(boostbook-dir) ;
-
- # Register generators only if we've were called via "using boostbook ; "
- generators.register-standard boostbook.dtdxml-to-boostbook : DTDXML : XML ;
- generators.register-standard boostbook.boostbook-to-docbook : XML : DOCBOOK ;
- generators.register-standard boostbook.boostbook-to-tests : XML : TESTS ;
- generators.register-standard boostbook.docbook-to-onehtml : DOCBOOK : HTML ;
- generators.register-standard boostbook.docbook-to-htmldir : DOCBOOK : HTMLDIR ;
- generators.register-standard boostbook.docbook-to-xhtmldir : DOCBOOK : XHTMLDIR ;
- generators.register-standard boostbook.docbook-to-htmlhelp : DOCBOOK : HTMLHELP ;
- generators.register-standard boostbook.docbook-to-manpages : DOCBOOK : MANPAGES ;
- generators.register-standard boostbook.docbook-to-fo : DOCBOOK : FO ;
-
- # The same about Jamfile main target rules.
- IMPORT $(__name__) : boostbook : : boostbook ;
- }
- else
- {
- if $(docbook-xsl-dir)
- {
- modify-config ;
- .docbook-xsl-dir = [ path.make $(docbook-xsl-dir) ] ;
- check-docbook-xsl-dir ;
- }
- if $(docbook-dtd-dir)
- {
- modify-config ;
- .docbook-dtd-dir = [ path.make $(docbook-dtd-dir) ] ;
- check-docbook-dtd-dir ;
- }
- if $(boostbook-dir)
- {
- modify-config ;
- check-boostbook-dir $(boostbook-dir) ;
- local boostbook-xsl-dir = [ path.glob $(boostbook-dir) : xsl ] ;
- local boostbook-dtd-dir = [ path.glob $(boostbook-dir) : dtd ] ;
- .boostbook-xsl-dir = $(boostbook-xsl-dir[1]) ;
- .boostbook-dtd-dir = $(boostbook-dtd-dir[1]) ;
- check-boostbook-xsl-dir ;
- check-boostbook-dtd-dir ;
- }
- }
-}
-
-rule lock-config ( )
-{
- if ! $(.initialized)
- {
- errors.user-error "BoostBook has not been configured." ;
- }
- if ! $(.config-locked)
- {
- .config-locked = true ;
- }
-}
-
-rule modify-config ( )
-{
- if $(.config-locked)
- {
- errors.user-error "BoostBook configuration cannot be changed after it has been used." ;
- }
+ check-boostbook-dir $(boostbook-dir) ;
+ find-tools $(docbook-xsl-dir) : $(docbook-dtd-dir) : $(boostbook-dir) ;
+
+ # Register generators only if we were called via "using boostbook ;"
+ local reg-gen = generators.register-standard ;
+ $(reg-gen) boostbook.dtdxml-to-boostbook : DTDXML : XML ;
+ $(reg-gen) boostbook.boostbook-to-docbook : XML : DOCBOOK ;
+ $(reg-gen) boostbook.boostbook-to-tests : XML : TESTS ;
+ $(reg-gen) boostbook.docbook-to-onehtml : DOCBOOK : HTML ;
+ $(reg-gen) boostbook.docbook-to-htmldir : DOCBOOK : HTMLDIR ;
+ $(reg-gen) boostbook.docbook-to-xhtmldir : DOCBOOK : XHTMLDIR ;
+ $(reg-gen) boostbook.docbook-to-htmlhelp : DOCBOOK : HTMLHELP ;
+ $(reg-gen) boostbook.docbook-to-manpages : DOCBOOK : MANPAGES ;
+ $(reg-gen) boostbook.docbook-to-fo : DOCBOOK : FO ;
+
+ # The same about Jamfile main target rules.
+ IMPORT $(__name__) : boostbook : : boostbook ;
+ }
+ else
+ {
+ if $(docbook-xsl-dir)
+ {
+ modify-config ;
+ .docbook-xsl-dir = [ path.make $(docbook-xsl-dir) ] ;
+ check-docbook-xsl-dir ;
+ }
+ if $(docbook-dtd-dir)
+ {
+ modify-config ;
+ .docbook-dtd-dir = [ path.make $(docbook-dtd-dir) ] ;
+ check-docbook-dtd-dir ;
+ }
+ if $(boostbook-dir)
+ {
+ modify-config ;
+ check-boostbook-dir $(boostbook-dir) ;
+ local boostbook-xsl-dir = [ path.glob $(boostbook-dir) : xsl ] ;
+ local boostbook-dtd-dir = [ path.glob $(boostbook-dir) : dtd ] ;
+ .boostbook-xsl-dir = $(boostbook-xsl-dir[1]) ;
+ .boostbook-dtd-dir = $(boostbook-dtd-dir[1]) ;
+ check-boostbook-xsl-dir ;
+ check-boostbook-dtd-dir ;
+ }
+ }
 }
 
-rule find-boost-in-registry ( keys * )
+
+local rule lock-config ( )
 {
- local boost-root = ;
- for local R in $(keys)
- {
- local installed-boost = [ W32_GETREG
- "HKEY_LOCAL_MACHINE\\SOFTWARE\\$(R)"
- : "InstallRoot" ] ;
- if $(installed-boost)
+ if ! $(.initialized)
+ {
+ import errors ;
+ errors.user-error BoostBook has not been configured. ;
+ }
+ if ! $(.config-locked)
     {
- boost-root += [ path.make $(installed-boost) ] ;
+ .config-locked = true ;
+
+ if $(.error-message)
+ {
+ print-error $(.error-message) ;
+ }
     }
- }
- return $(boost-root) ;
 }
 
-rule check-docbook-xsl-dir ( )
+
+local rule modify-config ( )
 {
- if $(.docbook-xsl-dir)
- {
- if ! [ path.glob $(.docbook-xsl-dir) : common/common.xsl ]
+ if $(.config-locked)
     {
- errors.user-error "BoostBook: could not find docbook XSL stylesheets in:" [ path.native $(.docbook-xsl-dir) ] ;
+ import errors ;
+ errors.user-error BoostBook configuration cannot be changed after it has
+ been used. ;
     }
- else
+}
+
+rule print-error ( location message * )
+{
+ ECHO error: at $(location) ;
+ ECHO error: $(message) ;
+ EXIT ;
+}
+
+rule make-error ( message * )
+{
+ return [ errors.nearest-user-location ] $(message) ;
+}
+
+
+rule find-boost-in-registry ( keys * )
+{
+ local boost-root ;
+ for local R in $(keys)
     {
- if --debug-configuration in [ modules.peek : ARGV ]
- {
- ECHO "notice: BoostBook: found docbook XSL stylesheets in:" [ path.native $(.docbook-xsl-dir) ] ;
- }
+ local installed-boost = [ W32_GETREG
+ "HKEY_LOCAL_MACHINE\\SOFTWARE\\$(R)" : "InstallRoot" ] ;
+ if $(installed-boost)
+ {
+ boost-root += [ path.make $(installed-boost) ] ;
+ }
     }
- }
+ return $(boost-root) ;
 }
 
-rule check-docbook-dtd-dir ( )
+
+rule check-docbook-xsl-dir ( )
 {
- if $(.docbook-dtd-dir)
- {
- if ! [ path.glob $(.docbook-dtd-dir) : docbookx.dtd ]
+ if $(.docbook-xsl-dir)
     {
- errors.user-error "error: BoostBook: could not find docbook DTD in:" [ path.native $(.docbook-dtd-dir) ] ;
+ if ! [ path.glob $(.docbook-xsl-dir) : common/common.xsl ]
+ {
+ import errors ;
+ .error-message = [ make-error BoostBook: could not find docbook XSL stylesheets
+ in: [ path.native $(.docbook-xsl-dir) ] ] ;
+ }
+ else if $(.debug-configuration)
+ {
+ ECHO notice: BoostBook: found docbook XSL stylesheets in: [
+ path.native $(.docbook-xsl-dir) ] ;
+ }
     }
- else
+}
+
+
+rule check-docbook-dtd-dir ( )
+{
+ if $(.docbook-dtd-dir)
     {
- if --debug-configuration in [ modules.peek : ARGV ]
- {
- ECHO "notice: BoostBook: found docbook DTD in:" [ path.native $(.docbook-dtd-dir) ] ;
- }
+ if ! [ path.glob $(.docbook-dtd-dir) : docbookx.dtd ]
+ {
+ import errors ;
+ .error-message = [ make-error BoostBook: could not find docbook DTD in: [
+ path.native $(.docbook-dtd-dir) ] ] ;
+ }
+ else if $(.debug-configuration)
+ {
+ ECHO notice: BoostBook: found docbook DTD in: [ path.native
+ $(.docbook-dtd-dir) ] ;
+ }
     }
- }
 }
 
+
 rule check-boostbook-xsl-dir ( )
 {
- if ! $(.boostbook-xsl-dir)
- {
- errors.user-error "error: BoostBook: could not find boostbook XSL stylesheets." ;
- }
- else if ! [ path.glob $(.boostbook-xsl-dir) : docbook.xsl ]
- {
- errors.user-error "error: BoostBook: could not find docbook XSL stylesheets in:" [ path.native $(.boostbook-xsl-dir) ] ;
- }
- else
- {
- if --debug-configuration in [ modules.peek : ARGV ]
+ if ! $(.boostbook-xsl-dir)
+ {
+ .error-message = [ make-error BoostBook: could not find boostbook XSL stylesheets. ] ;
+ }
+ else if ! [ path.glob $(.boostbook-xsl-dir) : docbook.xsl ]
+ {
+ .error-message = [ make-error BoostBook: could not find docbook XSL stylesheets in:
+ [ path.native $(.boostbook-xsl-dir) ] ] ;
+ }
+ else if $(.debug-configuration)
     {
- ECHO "notice: BoostBook: found boostbook XSL stylesheets in:" [ path.native $(.boostbook-xsl-dir) ] ;
+ ECHO notice: BoostBook: found boostbook XSL stylesheets in: [
+ path.native $(.boostbook-xsl-dir) ] ;
     }
- }
 }
 
+
 rule check-boostbook-dtd-dir ( )
 {
- if ! $(.boostbook-dtd-dir)
- {
- errors.user-error "error: BoostBook: could not find boostbook DTD." ;
- }
- else if ! [ path.glob $(.boostbook-dtd-dir) : boostbook.dtd ]
- {
- errors.user-error "error: BoostBook: could not find boostbook DTD in:" [ path.native $(.boostbook-dtd-dir) ] ;
- }
- else
- {
- if --debug-configuration in [ modules.peek : ARGV ]
+ if ! $(.boostbook-dtd-dir)
+ {
+ .error-message = [ make-error BoostBook: could not find boostbook DTD. ] ;
+ }
+ else if ! [ path.glob $(.boostbook-dtd-dir) : boostbook.dtd ]
     {
- ECHO "notice: BoostBook: found boostbook DTD in:" [ path.native $(.boostbook-dtd-dir) ] ;
+ .error-message = [ make-error BoostBook: could not find boostbook DTD in: [
+ path.native $(.boostbook-dtd-dir) ] ] ;
+ }
+ else if $(.debug-configuration)
+ {
+ ECHO notice: BoostBook: found boostbook DTD in: [ path.native
+ $(.boostbook-dtd-dir) ] ;
     }
- }
 }
 
+
 rule check-boostbook-dir ( boostbook-dir ? )
 {
- if $(boostbook-dir) && ! [ path.glob $(boostbook-dir) : xsl ]
- {
- errors.user-error "error: BoostBook: could not find boostbook in:" [ path.native $(boostbook-dir) ] ;
- }
+ if $(boostbook-dir) && ! [ path.glob $(boostbook-dir) : xsl ]
+ {
+ import errors ;
+ .error-message = [ make-error BoostBook: could not find boostbook in: [ path.native
+ $(boostbook-dir) ] ] ;
+ }
 }
 
+
 rule find-tools ( docbook-xsl-dir ? : docbook-dtd-dir ? : boostbook-dir ? )
 {
- docbook-xsl-dir ?= [ modules.peek : DOCBOOK_XSL_DIR ] ;
- docbook-dtd-dir ?= [ modules.peek : DOCBOOK_DTD_DIR ] ;
- boostbook-dir ?= [ modules.peek : BOOSTBOOK_DIR ] ;
-
- # Look for the boostbook stylesheets relative to BOOST_ROOT
- # and Boost.Build.
- local boost-build-root = [ path.make [ build-system.location ] ] ;
- local boostbook-search-dirs = [ path.join $(boost-build-root) .. .. ] ;
-
- local boost-root = [ modules.peek : BOOST_ROOT ] ;
- if $(boost-root)
- {
- boostbook-search-dirs += [ path.join [ path.make $(boost-root) ] tools ] ;
- }
- boostbook-dir ?= [ path.glob $(boostbook-search-dirs) : boostbook* ] ;
-
- # Try to find the tools in platform specific locations
- if [ os.name ] = NT
- {
- # If installed by the Boost installer.
- local boost-root = ;
-
- local boost-installer-versions = snapshot cvs 1.33.0 ;
- local boost-consulting-installer-versions = 1.33.1 1.34.0 1.34.1 ;
- local boostpro-installer-versions =
- 1.35.0 1.36.0 1.37.0 1.38.0 1.39.0 1.40.0 1.41.0 1.42.0
- 1.43.0 1.44.0 1.45.0 1.46.0 1.47.0 1.48.0 1.49.0 1.50.0 ;
-
- local old-installer-root = [ find-boost-in-registry Boost.org\\$(boost-installer-versions) ] ;
-
- # Make sure that the most recent version is searched for first
- boost-root += [ sequence.reverse
- [ find-boost-in-registry
- Boost-Consulting.com\\$(boost-consulting-installer-versions)
- boostpro.com\\$(boostpro-installer-versions) ] ] ;
-
- # Plausible locations.
- local root = [ PWD ] ;
- while $(root) != $(root:D) { root = $(root:D) ; }
- root = [ path.make $(root) ] ;
- local search-dirs = ;
- local docbook-search-dirs = ;
- for local p in $(boost-root) {
- search-dirs += [ path.join $(p) tools ] ;
- }
- for local p in $(old-installer-root)
- {
- search-dirs += [ path.join $(p) share ] ;
- docbook-search-dirs += [ path.join $(p) share ] ;
- }
- search-dirs += [ path.join $(root) Boost tools ] ;
- search-dirs += [ path.join $(root) Boost share ] ;
- docbook-search-dirs += [ path.join $(root) Boost share ] ;
-
- docbook-xsl-dir ?= [ path.glob $(docbook-search-dirs) : docbook-xsl* ] ;
- docbook-dtd-dir ?= [ path.glob $(docbook-search-dirs) : docbook-xml* ] ;
- boostbook-dir ?= [ path.glob $(search-dirs) : boostbook* ] ;
- }
- else
- {
- # Plausible locations.
-
- local share = /usr/local/share /usr/share /opt/share /opt/local/share ;
- local dtd-versions = 4.2 ;
-
- docbook-xsl-dir ?= [ path.glob $(share) : docbook-xsl* ] ;
- docbook-xsl-dir ?= [ path.glob $(share)/sgml/docbook : xsl-stylesheets ] ;
- docbook-xsl-dir ?= [ path.glob $(share)/xsl : docbook* ] ;
-
- docbook-dtd-dir ?= [ path.glob $(share) : docbook-xml* ] ;
- docbook-dtd-dir ?= [ path.glob $(share)/sgml/docbook : xml-dtd-$(dtd-versions)* ] ;
- docbook-dtd-dir ?= [ path.glob $(share)/xml/docbook : $(dtd-versions) ] ;
-
- boostbook-dir ?= [ path.glob $(share) : boostbook* ] ;
-
- # Ubuntu Linux
- docbook-xsl-dir ?= [ path.glob /usr/share/xml/docbook/stylesheet : nwalsh ] ;
- docbook-dtd-dir ?= [ path.glob /usr/share/xml/docbook/schema/dtd : $(dtd-versions) ] ;
-
- # SUSE
- docbook-xsl-dir ?= [ path.glob /usr/share/xml/docbook/stylesheet/nwalsh : current ] ;
- }
-
- if $(docbook-xsl-dir)
- {
- .docbook-xsl-dir = [ path.make $(docbook-xsl-dir[1]) ] ;
- }
- if $(docbook-dtd-dir)
- {
- .docbook-dtd-dir = [ path.make $(docbook-dtd-dir[1]) ] ;
- }
-
- if --debug-configuration in [ modules.peek : ARGV ]
- {
- ECHO "notice: Boost.Book: searching XSL/DTD in" ;
- ECHO "notice:" [ sequence.transform path.native : $(boostbook-dir) ] ;
- }
- local boostbook-xsl-dir ;
- for local dir in $(boostbook-dir) {
- boostbook-xsl-dir += [ path.glob $(dir) : xsl ] ;
- }
- local boostbook-dtd-dir ;
- for local dir in $(boostbook-dir) {
- boostbook-dtd-dir += [ path.glob $(dir) : dtd ] ;
- }
- .boostbook-xsl-dir = $(boostbook-xsl-dir[1]) ;
- .boostbook-dtd-dir = $(boostbook-dtd-dir[1]) ;
-
- check-docbook-xsl-dir ;
- check-docbook-dtd-dir ;
- check-boostbook-xsl-dir ;
- check-boostbook-dtd-dir ;
+ docbook-xsl-dir ?= [ modules.peek : DOCBOOK_XSL_DIR ] ;
+ docbook-dtd-dir ?= [ modules.peek : DOCBOOK_DTD_DIR ] ;
+ boostbook-dir ?= [ modules.peek : BOOSTBOOK_DIR ] ;
+
+ # Look for the boostbook stylesheets relative to BOOST_ROOT and Boost.Build.
+ local boost-build-root = [ path.make [ build-system.location ] ] ;
+ local boostbook-search-dirs = [ path.join $(boost-build-root) .. .. ] ;
+
+ local boost-root = [ modules.peek : BOOST_ROOT ] ;
+ if $(boost-root)
+ {
+ boostbook-search-dirs += [ path.join [ path.make $(boost-root) ] tools ]
+ ;
+ }
+ boostbook-dir ?= [ path.glob $(boostbook-search-dirs) : boostbook* ] ;
+
+ # Try to find the tools in platform specific locations.
+ if [ os.name ] = NT
+ {
+ # If installed by the Boost installer.
+ local boost-root = ;
+
+ local boost-installer-versions = snapshot cvs 1.33.0 ;
+ local boost-consulting-installer-versions = 1.33.1 1.34.0 1.34.1 ;
+ local boostpro-installer-versions =
+ 1.35.0 1.36.0 1.37.0 1.38.0 1.39.0 1.40.0 1.41.0 1.42.0
+ 1.43.0 1.44.0 1.45.0 1.46.0 1.47.0 1.48.0 1.49.0 1.50.0 ;
+
+ local old-installer-root = [ find-boost-in-registry
+ Boost.org\\$(boost-installer-versions) ] ;
+
+ # Make sure that the most recent version is searched for first.
+ boost-root += [ sequence.reverse [ find-boost-in-registry
+ Boost-Consulting.com\\$(boost-consulting-installer-versions)
+ boostpro.com\\$(boostpro-installer-versions) ] ] ;
+
+ # Plausible locations.
+ local root = [ PWD ] ;
+ while $(root) != $(root:D) { root = $(root:D) ; }
+ root = [ path.make $(root) ] ;
+ local search-dirs ;
+ local docbook-search-dirs ;
+ for local p in $(boost-root)
+ {
+ search-dirs += [ path.join $(p) tools ] ;
+ }
+ for local p in $(old-installer-root)
+ {
+ search-dirs += [ path.join $(p) share ] ;
+ docbook-search-dirs += [ path.join $(p) share ] ;
+ }
+ search-dirs += [ path.join $(root) Boost tools ] ;
+ search-dirs += [ path.join $(root) Boost share ] ;
+ docbook-search-dirs += [ path.join $(root) Boost share ] ;
+
+ docbook-xsl-dir ?= [ path.glob $(docbook-search-dirs) : docbook-xsl* ] ;
+ docbook-dtd-dir ?= [ path.glob $(docbook-search-dirs) : docbook-xml* ] ;
+ boostbook-dir ?= [ path.glob $(search-dirs) : boostbook* ] ;
+ }
+ else
+ {
+ # Plausible locations.
+
+ local share = /usr/local/share /usr/share /opt/share /opt/local/share ;
+ local dtd-versions = 4.2 ;
+
+ docbook-xsl-dir ?= [ path.glob $(share) : docbook-xsl* ] ;
+ docbook-xsl-dir ?= [ path.glob $(share)/sgml/docbook : xsl-stylesheets ]
+ ;
+ docbook-xsl-dir ?= [ path.glob $(share)/xsl : docbook* ] ;
+
+ docbook-dtd-dir ?= [ path.glob $(share) : docbook-xml* ] ;
+ docbook-dtd-dir ?= [ path.glob $(share)/sgml/docbook :
+ xml-dtd-$(dtd-versions)* ] ;
+ docbook-dtd-dir ?= [ path.glob $(share)/xml/docbook : $(dtd-versions) ]
+ ;
+
+ boostbook-dir ?= [ path.glob $(share) : boostbook* ] ;
+
+ # Ubuntu Linux.
+ docbook-xsl-dir ?= [ path.glob /usr/share/xml/docbook/stylesheet :
+ nwalsh ] ;
+ docbook-dtd-dir ?= [ path.glob /usr/share/xml/docbook/schema/dtd :
+ $(dtd-versions) ] ;
+
+ # SUSE.
+ docbook-xsl-dir ?= [ path.glob /usr/share/xml/docbook/stylesheet/nwalsh
+ : current ] ;
+ }
+
+ if $(docbook-xsl-dir)
+ {
+ .docbook-xsl-dir = [ path.make $(docbook-xsl-dir[1]) ] ;
+ }
+ if $(docbook-dtd-dir)
+ {
+ .docbook-dtd-dir = [ path.make $(docbook-dtd-dir[1]) ] ;
+ }
+
+ if $(.debug-configuration)
+ {
+ ECHO notice: Boost.Book: searching XSL/DTD "in" ;
+ ECHO notice: [ sequence.transform path.native : $(boostbook-dir) ] ;
+ }
+ local boostbook-xsl-dir ;
+ for local dir in $(boostbook-dir)
+ {
+ boostbook-xsl-dir += [ path.glob $(dir) : xsl ] ;
+ }
+ local boostbook-dtd-dir ;
+ for local dir in $(boostbook-dir)
+ {
+ boostbook-dtd-dir += [ path.glob $(dir) : dtd ] ;
+ }
+ .boostbook-xsl-dir = $(boostbook-xsl-dir[1]) ;
+ .boostbook-dtd-dir = $(boostbook-dtd-dir[1]) ;
+
+ check-docbook-xsl-dir ;
+ check-docbook-dtd-dir ;
+ check-boostbook-xsl-dir ;
+ check-boostbook-dtd-dir ;
 }
 
+
 rule xsl-dir
 {
- lock-config ;
- return $(.boostbook-xsl-dir) ;
+ lock-config ;
+ return $(.boostbook-xsl-dir) ;
 }
 
+
 rule dtd-dir
 {
- lock-config ;
- return $(.boostbook-dtd-dir) ;
+ lock-config ;
+ return $(.boostbook-dtd-dir) ;
 }
 
+
 rule docbook-xsl-dir
 {
- lock-config ;
- return $(.docbook-xsl-dir) ;
+ lock-config ;
+ return $(.docbook-xsl-dir) ;
 }
 
+
 rule docbook-dtd-dir
 {
- lock-config ;
- return $(.docbook-dtd-dir) ;
+ lock-config ;
+ return $(.docbook-dtd-dir) ;
 }
 
+
 rule dtdxml-to-boostbook ( target : source : properties * )
 {
- lock-config ;
- xslt $(target) : $(source) "$(.boostbook-xsl-dir)/dtd/dtd2boostbook.xsl"
- : $(properties) ;
+ lock-config ;
+ xsltproc.xslt $(target) : $(source)
+ "$(.boostbook-xsl-dir)/dtd/dtd2boostbook.xsl" : $(properties) ;
 }
 
+
 rule boostbook-to-docbook ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/docbook.xsl ] ;
- xslt $(target) : $(source) $(stylesheet) : $(properties) ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/docbook.xsl ] ;
+ xsltproc.xslt $(target) : $(source) $(stylesheet) : $(properties) ;
 }
 
+
 rule docbook-to-onehtml ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/html-single.xsl ] ;
- xslt $(target) : $(source) $(stylesheet) : $(properties) ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/html-single.xsl ] ;
+ xsltproc.xslt $(target) : $(source) $(stylesheet) : $(properties) ;
 }
 
+
 rule docbook-to-htmldir ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/html.xsl ] ;
- xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : html ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/html.xsl ] ;
+ xsltproc.xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : html
+ ;
 }
 
+
 rule docbook-to-xhtmldir ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/xhtml.xsl ] ;
- xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : xhtml ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/xhtml.xsl ] ;
+ xsltproc.xslt-dir $(target) : $(source) $(stylesheet) : $(properties) :
+ xhtml ;
 }
 
+
 rule docbook-to-htmlhelp ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/html-help.xsl ] ;
- xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : htmlhelp ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/html-help.xsl ] ;
+ xsltproc.xslt-dir $(target) : $(source) $(stylesheet) : $(properties) :
+ htmlhelp ;
 }
 
+
 rule docbook-to-manpages ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/manpages.xsl ] ;
- xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : man ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/manpages.xsl ] ;
+ xsltproc.xslt-dir $(target) : $(source) $(stylesheet) : $(properties) : man
+ ;
 }
 
+
 rule docbook-to-fo ( target : source : properties * )
 {
- lock-config ;
- local stylesheet = [ path.native $(.boostbook-xsl-dir)/fo.xsl ] ;
- xslt $(target) : $(source) $(stylesheet) : $(properties) ;
+ lock-config ;
+ local stylesheet = [ path.native $(.boostbook-xsl-dir)/fo.xsl ] ;
+ xsltproc.xslt $(target) : $(source) $(stylesheet) : $(properties) ;
 }
 
+
 rule format-catalog-path ( path )
 {
     local result = $(path) ;
@@ -474,257 +529,245 @@
     return [ regex.replace $(result) " " "%20" ] ;
 }
 
+
 rule generate-xml-catalog ( target : sources * : properties * )
 {
- print.output $(target) ;
+ print.output $(target) ;
 
- # BoostBook DTD catalog entry
- local boostbook-dtd-dir = [ boostbook.dtd-dir ] ;
- if $(boostbook-dtd-dir)
- {
- boostbook-dtd-dir = [ format-catalog-path $(boostbook-dtd-dir) ] ;
- }
-
- print.text
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE catalog "
- " PUBLIC \"-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN\""
- " \"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd\">"
- "<catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\">"
- " <rewriteURI uriStartString=\"http://www.boost.org/tools/boostbook/dtd/\" rewritePrefix=\"file://$(boostbook-dtd-dir)/\"/>"
- : true ;
-
- local docbook-xsl-dir = [ boostbook.docbook-xsl-dir ] ;
- if ! $(docbook-xsl-dir)
- {
- ECHO "BoostBook warning: no DocBook XSL directory specified." ;
- ECHO " If you have the DocBook XSL stylesheets installed, please " ;
- ECHO " set DOCBOOK_XSL_DIR to the stylesheet directory on either " ;
- ECHO " the command line (via -sDOCBOOK_XSL_DIR=...) or in a " ;
- ECHO " Boost.Jam configuration file. The DocBook XSL stylesheets " ;
- ECHO " are available here: http://docbook.sourceforge.net/ " ;
- ECHO " Stylesheets will be downloaded on-the-fly (very slow!) " ;
- }
- else
- {
- docbook-xsl-dir = [ format-catalog-path $(docbook-xsl-dir) ] ;
- print.text " <rewriteURI uriStartString=\"http://docbook.sourceforge.net/release/xsl/current/\" rewritePrefix=\"file://$(docbook-xsl-dir)/\"/>" ;
- }
-
- local docbook-dtd-dir = [ boostbook.docbook-dtd-dir ] ;
- if ! $(docbook-dtd-dir)
- {
- ECHO "BoostBook warning: no DocBook DTD directory specified." ;
- ECHO " If you have the DocBook DTD installed, please set " ;
- ECHO " DOCBOOK_DTD_DIR to the DTD directory on either " ;
- ECHO " the command line (via -sDOCBOOK_DTD_DIR=...) or in a " ;
- ECHO " Boost.Jam configuration file. The DocBook DTD is available " ;
- ECHO " here: http://www.oasis-open.org/docbook/xml/4.2/index.shtml" ;
- ECHO " The DTD will be downloaded on-the-fly (very slow!) " ;
- }
- else
- {
- docbook-dtd-dir = [ format-catalog-path $(docbook-dtd-dir) ] ;
- print.text " <rewriteURI uriStartString=\"http://www.oasis-open.org/docbook/xml/4.2/\" rewritePrefix=\"file://$(docbook-dtd-dir)/\"/>" ;
- }
+ # BoostBook DTD catalog entry.
+ local boostbook-dtd-dir = [ boostbook.dtd-dir ] ;
+ if $(boostbook-dtd-dir)
+ {
+ boostbook-dtd-dir = [ format-catalog-path $(boostbook-dtd-dir) ] ;
+ }
+
+ print.text
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE catalog "
+ " PUBLIC \"-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN\""
+ " \"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd\">"
+ "<catalog xmlns=\"urn:oasis:names:tc:entity:xmlns:xml:catalog\">"
+ " <rewriteURI uriStartString=\"http://www.boost.org/tools/boostbook/dtd/\" rewritePrefix=\"file://$(boostbook-dtd-dir)/\"/>"
+ : true ;
+
+ local docbook-xsl-dir = [ boostbook.docbook-xsl-dir ] ;
+ if ! $(docbook-xsl-dir)
+ {
+ ECHO "BoostBook warning: no DocBook XSL directory specified." ;
+ ECHO " If you have the DocBook XSL stylesheets installed, please " ;
+ ECHO " set DOCBOOK_XSL_DIR to the stylesheet directory on either " ;
+ ECHO " the command line (via -sDOCBOOK_XSL_DIR=...) or in a " ;
+ ECHO " Boost.Jam configuration file. The DocBook XSL stylesheets " ;
+ ECHO " are available here: http://docbook.sourceforge.net/ " ;
+ ECHO " Stylesheets will be downloaded on-the-fly (very slow!) " ;
+ }
+ else
+ {
+ docbook-xsl-dir = [ format-catalog-path $(docbook-xsl-dir) ] ;
+ print.text " <rewriteURI uriStartString=\"http://docbook.sourceforge.net/release/xsl/current/\" rewritePrefix=\"file://$(docbook-xsl-dir)/\"/>" ;
+ }
 
- print.text "</catalog>" ;
+ local docbook-dtd-dir = [ boostbook.docbook-dtd-dir ] ;
+ if ! $(docbook-dtd-dir)
+ {
+ ECHO "BoostBook warning: no DocBook DTD directory specified." ;
+ ECHO " If you have the DocBook DTD installed, please set " ;
+ ECHO " DOCBOOK_DTD_DIR to the DTD directory on either " ;
+ ECHO " the command line (via -sDOCBOOK_DTD_DIR=...) or in a " ;
+ ECHO " Boost.Jam configuration file. The DocBook DTD is available " ;
+ ECHO " here: http://www.oasis-open.org/docbook/xml/4.2/index.shtml" ;
+ ECHO " The DTD will be downloaded on-the-fly (very slow!) " ;
+ }
+ else
+ {
+ docbook-dtd-dir = [ format-catalog-path $(docbook-dtd-dir) ] ;
+ print.text " <rewriteURI uriStartString=\"http://www.oasis-open.org/docbook/xml/4.2/\" rewritePrefix=\"file://$(docbook-dtd-dir)/\"/>" ;
+ }
+
+ print.text "</catalog>" ;
 }
 
-rule xml-catalog ( )
+
+# Returns information about the global XML catalog target, creating it lazily if
+# needed. To get the global catalog generated only once we do not create it in
+# every project that requests it but instead only create it based on the first
+# project requesting it and then reuse it from there for any later requests.
+#
+# To get 'as close as possible' to having the global catalog stored in the same
+# location independent of which folder our build was run from, we assign its
+# target to the given project's base Jamroot project. This works correctly as
+# long as we know the passed project is not standalone or one of Boost Build's
+# configuration module projects, as those to not have a Jamroot project in their
+# parent chain. Note also that we can still get our targets generated in
+# different folders in case when one build project references a target from
+# another build project with its own separate Jamroot.
+#
+# FIXME: Ideally the catalog target should be created as part of the boostbook
+# project and stored in some central location for all used standalone pojects,
+# shared between all builds made on that system. This however would require much
+# more though to add the necessary changes to Boost Build's internal design.
+#
+local rule xml-catalog ( project )
 {
     if ! $(.xml-catalog)
     {
- # The target is created as part of the root project. But ideally
- # it would be created as part of the boostbook project. This is not
- # current possible as such global projects don't inherit things like
- # the build directory.
-
- # Find the root project.
- local root-project = [ project.current ] ;
- root-project = [ $(root-project).project-module ] ;
- while
- [ project.attribute $(root-project) parent-module ] &&
- [ project.attribute $(root-project) parent-module ] != user-config &&
- [ project.attribute $(root-project) parent-module ] != project-config
- {
- root-project = [ project.attribute $(root-project) parent-module ] ;
- }
- .xml-catalog = [ new file-target boostbook_catalog
- : XML
- : [ project.target $(root-project) ]
- : [ new action : boostbook.generate-xml-catalog ]
- :
- ] ;
+ local project-module = [ $(project).project-module ] ;
+ local root-module = [ project.get-jamroot-module $(project-module) ] ;
+ if ! $(root-module)
+ {
+ import errors ;
+ if [ project.is-config-module $(project-module) ]
+ {
+ errors.user-error boostbook targets can not be declared in Boost
+ Build's configuration modules. ;
+ }
+ else
+ {
+ errors.user-error boostbook targets can not be declared in
+ standalone projects. : use a Jamfile/Jamroot project
+ instead. ;
+ }
+ }
+ local root-project = [ project.target $(root-module) ] ;
+
+ .xml-catalog = [ virtual-target.register [ new file-target
+ boostbook_catalog : XML : $(root-project) : [ new action :
+ boostbook.generate-xml-catalog ] ] ] ;
         .xml-catalog-file = [ $(.xml-catalog).path ] [ $(.xml-catalog).name ] ;
         .xml-catalog-file = $(.xml-catalog-file:J=/) ;
     }
     return $(.xml-catalog) $(.xml-catalog-file) ;
 }
 
-class boostbook-generator : generator
+
+class boostbook-target-class : basic-target
 {
- import feature ;
- import virtual-target ;
     import generators ;
- import boostbook ;
-
-
- rule __init__ ( * : * )
- {
- generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
- }
-
- rule run ( project name ? : property-set : sources * )
+ import property-set ;
+ import virtual-target ;
+
+ rule construct ( name : sources * : property-set )
     {
- # Generate the catalog, but only once...
- local global-catalog = [ boostbook.xml-catalog ] ;
+ # Generate the catalog, but only once.
+ IMPORT boostbook : xml-catalog : $(__name__) : boostbook.xml-catalog ;
+ local global-catalog = [ boostbook.xml-catalog [ project ] ] ;
         local catalog = $(global-catalog[1]) ;
         local catalog-file = $(global-catalog[2]) ;
         local targets ;
-
- # Add the catalog to the property set
+
+ # Add the catalog to the property set.
         property-set = [ $(property-set).add-raw <catalog>$(catalog-file) ] ;
 
         local type = none ;
- local manifest ;
+ local manifest ;
         local format = [ $(property-set).get <format> ] ;
- switch $(format)
+ switch $(format)
         {
- case html :
- {
- type = HTMLDIR ;
- manifest = HTML.manifest ;
- }
- case xhtml :
- {
- type = XHTMLDIR ;
- manifest = HTML.manifest ;
- }
- case htmlhelp :
- {
- type = HTMLHELP ;
- manifest = HTML.manifest ;
- }
-
- case onehtml : type = HTML ;
-
- case man :
- {
- type = MANPAGES ;
- manifest = man.manifest ;
- }
-
- case docbook : type = DOCBOOK ;
- case fo : type = FO ;
- case pdf : type = PDF ;
- case ps : type = PS ;
- case tests : type = TESTS ;
+ case html : type = HTMLDIR ; manifest = HTML.manifest ;
+ case xhtml : type = XHTMLDIR ; manifest = HTML.manifest ;
+ case htmlhelp : type = HTMLHELP ; manifest = HTML.manifest ;
+ case onehtml : type = HTML ;
+ case man : type = MANPAGES ; manifest = man.manifest ;
+ case docbook : type = DOCBOOK ;
+ case fo : type = FO ;
+ case pdf : type = PDF ;
+ case ps : type = PS ;
+ case tests : type = TESTS ;
         }
-
+
+ local target ;
         if $(manifest)
         {
- # Create DOCBOOK file from BOOSTBOOK sources.
- local base-target = [ generators.construct $(project)
- : DOCBOOK : $(property-set) : $(sources) ] ;
- base-target = $(base-target[2]) ;
- $(base-target).depends $(catalog) ;
-
- # Generate HTML/PDF/PS from DOCBOOK.
- local target = [ generators.construct $(project) $(name)_$(manifest)
- : $(type)
- : [ $(property-set).add-raw
- <xsl:param>manifest=$(name)_$(manifest) ]
- : $(base-target) ] ;
+ # Sources --> DOCBOOK.
+ local docbook-target = [ generators.construct [ project ] : DOCBOOK
+ : $(property-set) : $(sources) ] ;
+ docbook-target = $(docbook-target[2]) ;
+ $(docbook-target).depends $(catalog) ;
+
+ # DOCBOOK --> type.
+ target = [ generators.construct [ project ] $(name)_$(manifest) :
+ $(type) : [ $(property-set).add-raw
+ <xsl:param>manifest=$(name)_$(manifest) ] : $(docbook-target) ]
+ ;
+ target = $(target[2]) ;
             local name = [ $(property-set).get <name> ] ;
             name ?= $(format) ;
- $(target[2]).set-path $(name) ;
- $(target[2]).depends $(catalog) ;
-
- targets += $(target[2]) ;
+ $(target).set-path $(name) ;
         }
- else {
- local target = [ generators.construct $(project)
- : $(type) : $(property-set) : $(sources) ] ;
-
+ else
+ {
+ # Sources --> type.
+ target = [ generators.construct [ project ] : $(type) :
+ $(property-set) : $(sources) ] ;
+ target = $(target[2]) ;
             if ! $(target)
             {
- errors.error "Cannot build documentation type '$(format)'" ;
- }
- else
- {
- $(target[2]).depends $(catalog) ;
- targets += $(target[2]) ;
+ import errors ;
+ errors.error Cannot build documentation type '$(format)'. ;
             }
         }
-
- return $(targets) ;
+ $(target).depends $(catalog) ;
+
+ return [ property-set.empty ] $(target) ;
     }
 }
 
-generators.register [ new boostbook-generator boostbook.main : : BOOSTBOOK_MAIN ] ;
 
-# Creates a boostbook target.
+# Declare a boostbook target.
+#
 rule boostbook ( target-name : sources * : requirements * : default-build * )
-{
- local project = [ project.current ] ;
-
- targets.main-target-alternative
- [ new typed-target $(target-name) : $(project) : BOOSTBOOK_MAIN
- : [ targets.main-target-sources $(sources) : $(target-name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+{
+ return [ targets.create-metatarget boostbook-target-class :
+ [ project.current ] : $(target-name) : $(sources) : $(requirements) :
+ $(default-build) ] ;
 }
 
+
+rule boostbook-to-tests ( target : source : properties * )
+{
+ lock-config ;
+ local boost_root = [ modules.peek : BOOST_ROOT ] ;
+ local native-path = [ path.native [ path.join $(.boostbook-xsl-dir) testing
+ Jamfile ] ] ;
+ local stylesheet = $(native-path:S=.xsl) ;
+ xsltproc.xslt $(target) : $(source) $(stylesheet) : $(properties)
+ <xsl:param>boost.root=$(boost_root) ;
+}
+
+
 #############################################################################
 # Dependency scanners
 #############################################################################
-# XInclude scanner. Mostly stolen from c-scanner :)
-# Note that this assumes an "xi" prefix for XIncludes. This isn't always the
-# case for XML documents, but we'll assume it's true for anything we encounter.
-class xinclude-scanner : scanner
+# XInclude scanner. Mostly stolen from c-scanner. :)
+# Note that this assumes an "xi" prefix for XIncludes. This is not always the
+# case for XML documents, but we assume it is true for anything we encounter.
+#
+class xinclude-scanner : scanner
 {
- import virtual-target ;
- import path ;
     import scanner ;
-
+
     rule __init__ ( includes * )
     {
         scanner.__init__ ;
         self.includes = $(includes) ;
     }
-
- rule pattern ( )
- {
- return "xi:include[ ]*href=\"([^\"]*)\"" ;
- }
-
- rule process ( target : matches * : binding )
- {
- local target_path = [ NORMALIZE_PATH $(binding:D) ] ;
-
- NOCARE $(matches) ;
- INCLUDES $(target) : $(matches) ;
- SEARCH on $(matches) = $(target_path) $(self.includes:G=) ;
-
- scanner.propagate $(__name__) : $(matches) : $(target) ;
- }
-}
 
-scanner.register xinclude-scanner : xsl:path ;
-type.set-scanner XML : xinclude-scanner ;
+ rule pattern ( )
+ {
+ return "xi:include[ ]*href=\"([^\"]*)\"" ;
+ }
 
-rule boostbook-to-tests ( target : source : properties * )
-{
- lock-config ;
- local boost_root = [ modules.peek : BOOST_ROOT ] ;
- local native-path =
- [ path.native [ path.join $(.boostbook-xsl-dir) testing Jamfile ] ] ;
- local stylesheet = $(native-path:S=.xsl) ;
- xslt $(target) : $(source) $(stylesheet)
- : $(properties) <xsl:param>boost.root=$(boost_root)
- ;
-}
+ rule process ( target : matches * : binding )
+ {
+ local target_path = [ NORMALIZE_PATH $(binding:D) ] ;
 
+ NOCARE $(matches) ;
+ INCLUDES $(target) : $(matches) ;
+ SEARCH on $(matches) = $(target_path) $(self.includes:G=) ;
 
+ scanner.propagate $(__name__) : $(matches) : $(target) ;
+ }
+}
+
+scanner.register xinclude-scanner : xsl:path ;
+type.set-scanner XML : xinclude-scanner ;

Modified: branches/release/tools/build/v2/tools/builtin.jam
==============================================================================
--- branches/release/tools/build/v2/tools/builtin.jam (original)
+++ branches/release/tools/build/v2/tools/builtin.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -4,7 +4,8 @@
 # Copyright 2005 Toon Knapen
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Defines standard features and rules.
 
@@ -39,13 +40,13 @@
 import generate ;
 
 
-.os-names = aix bsd cygwin darwin freebsd hpux iphone linux netbsd
- openbsd osf qnx qnxnto sgi solaris unix unixware windows
- elf # Not actually an OS -- used for targeting bare metal where
- # object format is ELF. This catches both -elf and -eabi gcc
- # targets and well as other compilers targeting ELF. It is not
- # clear how often do we need to key of ELF specifically as opposed
- # to other bare metal targets, but let's stick with gcc naming.
+.os-names = aix bsd cygwin darwin freebsd hpux iphone linux netbsd openbsd osf
+ qnx qnxnto sgi solaris unix unixware windows
+ elf # Not actually an OS -- used for targeting bare metal where object
+ # format is ELF. This catches both -elf and -eabi gcc targets and well
+ # as other compilers targeting ELF. It is not clear how often we need
+ # the 'elf' key as opposed to other bare metal targets, but let us
+ # stick with gcc naming.
     ;
 
 # Feature used to determine which OS we're on. New <target-os> and <host-os>
@@ -300,6 +301,7 @@
 
     # Advanced RISC Machines
     armv2 armv2a armv3 armv3m armv4 armv4t armv5 armv5t armv5te armv6 armv6j iwmmxt ep9312
+ armv7 armv7s
 
     : propagated optional ;
 
@@ -439,7 +441,9 @@
 {
     rule __init__ ( * : * )
     {
- generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8)
+ : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) :
+ $(17) : $(18) : $(19) ;
     }
 
     rule run ( project name ? : property-set : sources * )
@@ -590,7 +594,9 @@
 {
     rule __init__ ( * : * )
     {
- generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8)
+ : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) :
+ $(17) : $(18) : $(19) ;
     }
 
     rule run ( project name ? : property-set : sources * )

Modified: branches/release/tools/build/v2/tools/cast.jam
==============================================================================
--- branches/release/tools/build/v2/tools/cast.jam (original)
+++ branches/release/tools/build/v2/tools/cast.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -24,7 +24,6 @@
 # > simpler than defining a main target rule.
 
 import "class" : new ;
-import errors ;
 import project ;
 import property-set ;
 import targets ;
@@ -49,12 +48,12 @@
         {
             if ! [ class.is-a $(s) : file-target ]
             {
- import errors ;
+ import errors : user-error : errors.user-error ;
                 errors.user-error Source to the 'cast' rule is not a file! ;
             }
             if [ $(s).action ]
             {
- import errors ;
+ import errors : user-error : errors.user-error ;
                 errors.user-error Only non-derived target are allowed for
                     'cast'. : when building [ full-name ] ;
             }
@@ -74,6 +73,7 @@
     local real-type = [ type.type-from-rule-name $(type) ] ;
     if ! $(real-type)
     {
+ import errors ;
         errors.user-error No type corresponds to the main target rule name
             '$(type)' : "Hint: try a lowercase name" ;
     }

Modified: branches/release/tools/build/v2/tools/clang-linux.jam
==============================================================================
--- branches/release/tools/build/v2/tools/clang-linux.jam (original)
+++ branches/release/tools/build/v2/tools/clang-linux.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -67,7 +67,7 @@
 # Flags
 
 toolset.flags clang-linux.compile OPTIONS <cflags> ;
-toolset.flags clang-linux.compile OPTIONS <cxxflags> ;
+toolset.flags clang-linux.compile.c++ OPTIONS <cxxflags> ;
 
 toolset.flags clang-linux.compile OPTIONS <optimization>off : ;
 toolset.flags clang-linux.compile OPTIONS <optimization>speed : -O3 ;
@@ -99,10 +99,10 @@
 
   if $(pth-file) {
     DEPENDS $(<) : $(pth-file) ;
- compile.c++.with-pch $(targets) : $(sources) ;
+ clang-linux.compile.c++.with-pch $(targets) : $(sources) ;
   }
   else {
- compile.c++.without-pth $(targets) : $(sources) ;
+ clang-linux.compile.c++.without-pth $(targets) : $(sources) ;
   }
 }
 
@@ -125,10 +125,10 @@
 
   if $(pth-file) {
     DEPENDS $(<) : $(pth-file) ;
- compile.c.with-pch $(targets) : $(sources) ;
+ clang-linux.compile.c.with-pch $(targets) : $(sources) ;
   }
   else {
- compile.c.without-pth $(targets) : $(sources) ;
+ clang-linux.compile.c.without-pth $(targets) : $(sources) ;
   }
 }
 

Modified: branches/release/tools/build/v2/tools/common.jam
==============================================================================
--- branches/release/tools/build/v2/tools/common.jam (original)
+++ branches/release/tools/build/v2/tools/common.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -268,8 +268,9 @@
         command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ;
         if ! $(command) && $(.debug-configuration)
         {
- ECHO "warning: toolset $(toolset) initialization: can not find tool $(tool)" ;
- ECHO "warning: initialized from" [ errors.nearest-user-location ] ;
+ ECHO warning: toolset $(toolset) initialization: can not find tool
+ $(tool) ;
+ ECHO warning: initialized from [ errors.nearest-user-location ] ;
         }
     }
     else
@@ -277,9 +278,10 @@
         command = [ check-tool $(user-provided-command) ] ;
         if ! $(command) && $(.debug-configuration)
         {
- ECHO "warning: toolset $(toolset) initialization: " ;
- ECHO "warning: can not find user-provided command " '$(user-provided-command)' ;
- ECHO "warning: initialized from" [ errors.nearest-user-location ] ;
+ ECHO warning: toolset $(toolset) initialization: ;
+ ECHO warning: can not find user-provided command
+ '$(user-provided-command)' ;
+ ECHO warning: initialized from [ errors.nearest-user-location ] ;
         }
     }
 
@@ -322,7 +324,8 @@
     }
     else
     {
- local m = [ GLOB [ modules.peek : PATH Path path ] : $(command) $(command).exe ] ;
+ local m = [ GLOB [ modules.peek : PATH Path path ] : $(command)
+ $(command).exe ] ;
         return $(m[1]:D) ;
     }
 }
@@ -330,15 +333,16 @@
 
 # Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'.
 # If found in PATH, returns 'name' and if found in additional paths, returns
-# absolute name. If the tool is found in several directories, returns the
-# first path found. Otherwise, returns an empty string. If 'path-last' is
-# specified, PATH is searched after 'additional-paths'.
+# absolute name. If the tool is found in several directories, returns the first
+# path found. Otherwise, returns an empty string. If 'path-last' is specified,
+# PATH is searched after 'additional-paths'.
 #
 rule find-tool ( name : additional-paths * : path-last ? )
 {
     local path = [ path.programs-path ] ;
     local match = [ path.glob $(path) : $(name) $(name).exe ] ;
- local additional-match = [ path.glob $(additional-paths) : $(name) $(name).exe ] ;
+ local additional-match = [ path.glob $(additional-paths) : $(name)
+ $(name).exe ] ;
 
     local result ;
     if $(path-last)
@@ -366,7 +370,6 @@
     }
 }
 
-
 # Checks if 'command' can be found either in path or is a full name to an
 # existing file.
 #
@@ -421,7 +424,8 @@
 {
     if $(.debug-configuration)
     {
- ECHO "notice: will use '$(command)' for $(toolset), condition $(condition:E=(empty))" ;
+ ECHO notice: will use '$(command)' for $(toolset), condition
+ $(condition:E=(empty)) ;
     }
 
     # The last parameter ('unchecked') says it is OK to set flags for another
@@ -469,10 +473,10 @@
     CP = copy /b ;
     IGNORE = "2>nul >nul & setlocal" ;
     LN ?= $(CP) ;
- # Ugly hack to convince copy to set the timestamp of the
- # destination to the current time by concatenating the
- # source with a nonexistent file. Note that this requires
- # /b (binary) as the default when concatenating files is /a (ascii).
+ # Ugly hack to convince copy to set the timestamp of the destination to the
+ # current time by concatenating the source with a nonexistent file. Note
+ # that this requires /b (binary) as the default when concatenating files is
+ # /a (ascii).
     WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ;
 }
 else
@@ -495,17 +499,17 @@
 }
 
 
-if "\n" = "n"
-{
- # Escape characters are not supported. Use ugly hacks that won't work,
- # see below.
+if "\n" = "n"
+{
+ # Escape characters not supported so use ugly hacks. Will not work on Cygwin
+ # - see below.
     nl = "
 " ;
     q = "" ;
 }
 else
 {
- nl = "\n" ;
+ nl = "\n" ;
     q = "\"" ;
 }
 
@@ -523,10 +527,10 @@
     }
     else
     {
- # If we don't have escape characters support in bjam, the below blows
- # up on CYGWIN, since the $(nl) variable holds a Windows new-line \r\n
- # sequence that messes up the executed export command which then reports
- # that the passed variable name is incorrect.
+ # If we do not have escape character support in bjam, the cod below
+ # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line
+ # \r\n sequence that messes up the executed export command which then
+ # reports that the passed variable name is incorrect.
         # But we have a check for cygwin in kernel/bootstrap.jam already.
         return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ;
     }
@@ -760,26 +764,26 @@
         {
             case <base> :
                 result += $(name:B) ;
-
+
             case <toolset> :
                 result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) :
- $(property-set) ] ] ;
-
+ $(property-set) ] ] ;
+
             case <threading> :
                 result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type)
- : $(property-set) ] ] ;
-
+ : $(property-set) ] ] ;
+
             case <runtime> :
                 result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) :
- $(property-set) ] ] ;
-
+ $(property-set) ] ] ;
+
             case <qt> :
- result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
- $(property-set) ] ] ;
+ result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
+ $(property-set) ] ] ;
 
             case <address-model> :
- result += [ join-tag $(f:G=) : [ address-model-tag $(name) : $(type) :
- $(property-set) ] ] ;
+ result += [ join-tag $(f:G=) : [ address-model-tag $(name) :
+ $(type) : $(property-set) ] ] ;
 
             case <version:*> :
                 local key = [ MATCH <version:(.*)> : $(f:G) ] ;
@@ -804,9 +808,8 @@
                 result += $(f:G=) ;
         }
     }
- result = [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
- $(property-set) ] ;
- return $(result) ;
+ return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
+ $(property-set) ] ;
 }
 
 
@@ -865,7 +868,7 @@
         case tru64cxx* : tag += tru ;
         case vacpp* : tag += xlc ;
     }
- local version = [ MATCH "<toolset.*version>([0123456789]+)[.]([0123456789]*)"
+ local version = [ MATCH <toolset.*version>([0123456789]+)[.]([0123456789]*)
         : $(properties) ] ;
     # For historical reasons, vc6.0 and vc7.0 use different naming.
     if $(tag) = vc
@@ -902,11 +905,10 @@
 
 local rule threading-tag ( name : type ? : property-set )
 {
- local tag = ;
- local properties = [ $(property-set).raw ] ;
- if <threading>multi in $(properties) { tag = mt ; }
-
- return $(tag:J=) ;
+ if <threading>multi in [ $(property-set).raw ]
+ {
+ return mt ;
+ }
 }
 
 
@@ -937,26 +939,25 @@
     return $(tag:J=) ;
 }
 
+
 # Create a tag for the Qt library version
 # "<qt>4.6.0" will result in tag "qt460"
 local rule qt-tag ( name : type ? : property-set )
 {
- local properties = [ $(property-set).get <qt> ] ;
- local version = [ MATCH "([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*)"
- : $(properties) ] ;
- local tag = "qt"$(version:J=) ;
- return $(tag) ;
+ local v = [ MATCH ([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*) :
+ [ $(property-set).get <qt> ] ] ;
+ return qt$(v:J=) ;
 }
 
+
 # Create a tag for the address-model
 # <address-model>64 will simply generate "64"
 local rule address-model-tag ( name : type ? : property-set )
 {
- local tag = ;
- local version = [ $(property-set).get <address-model> ] ;
- return $(version) ;
+ return [ $(property-set).get <address-model> ] ;
 }
 
+
 rule __test__ ( )
 {
     import assert ;
@@ -964,18 +965,14 @@
     local save-os = [ modules.peek os : .name ] ;
 
     modules.poke os : .name : LINUX ;
-
     assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
         : path-variable-setting-command PATH : foo bar baz ;
-
     assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
         : prepend-path-variable-command PATH : foo bar ;
 
     modules.poke os : .name : NT ;
-
     assert.result "set PATH=foo;bar;baz\n"
         : path-variable-setting-command PATH : foo bar baz ;
-
     assert.result "set PATH=foo;bar;%PATH%\n"
         : prepend-path-variable-command PATH : foo bar ;
 

Modified: branches/release/tools/build/v2/tools/cray.jam
==============================================================================
--- branches/release/tools/build/v2/tools/cray.jam (original)
+++ branches/release/tools/build/v2/tools/cray.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -63,6 +63,9 @@
 flags cray.compile INCLUDES <include> ;
 flags cray.link OPTIONS <linkflags> ;
 
+flags cray.compile OPTIONS <link>shared : -fPIC ;
+flags cray.link OPTIONS <link>shared : -fPIC ;
+
 flags cray.link LIBPATH <library-path> ;
 flags cray.link LIBRARIES <library-file> ;
 flags cray.link FINDLIBS-ST <find-static-library> ;

Modified: branches/release/tools/build/v2/tools/darwin.jam
==============================================================================
--- branches/release/tools/build/v2/tools/darwin.jam (original)
+++ branches/release/tools/build/v2/tools/darwin.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -35,6 +35,8 @@
 
 #############################################################################
 
+_ = " " ;
+
 if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
 {
     .debug-configuration = true ;
@@ -376,6 +378,7 @@
 {
     local ps = [ property-set.create $(properties) ] ;
     local arch = [ $(ps).get <architecture> ] ;
+ local instruction-set = [ $(ps).get <instruction-set> ] ;
     local address-model = [ $(ps).get <address-model> ] ;
     local osx-version = [ $(ps).get <macosx-version> ] ;
     local gcc-version = [ $(ps).get <toolset-darwin:version> ] ;
@@ -454,8 +457,12 @@
         
         case arm :
         {
- options = -arch armv6 ;
- }
+ if $(instruction-set) {
+ options = -arch$(_)$(instruction-set) ;
+ } else {
+ options = -arch arm ;
+ }
+ }
     }
     
     if $(options)
@@ -526,8 +533,6 @@
 # uncomment to see what libtool is doing under the hood
 #~ flags darwin.link.dll OPTIONS : -Wl,-v ;
 
-_ = " " ;
-
 # set up the -F option to include the paths to any frameworks used.
 local rule prepare-framework-path ( target + )
 {

Modified: branches/release/tools/build/v2/tools/doxygen.jam
==============================================================================
--- branches/release/tools/build/v2/tools/doxygen.jam (original)
+++ branches/release/tools/build/v2/tools/doxygen.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 # Copyright 2003, 2004, 2005 Vladimir Prus
 # Copyright 2006 Rene Rivera
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # This module defines rules to handle generation of various outputs from source
 # files documented with doxygen comments. The supported transformations are:
@@ -17,32 +18,30 @@
 # <target> with the Doxygen html files, and a <target>.html file redirecting to
 # that directory.
 
+import alias ;
+import boostbook ;
 import "class" : new ;
-import targets ;
+import common ;
 import feature ;
-import property ;
+import make ;
+import modules ;
 import generators ;
-import boostbook ;
-import type ;
+import os ;
 import path ;
 import print ;
-import regex ;
-import stage ;
-import project ;
-import xsltproc ;
-import make ;
-import os ;
-import toolset : flags ;
-import alias ;
-import common ;
-import modules ;
 import project ;
+import property ;
+import stage ;
+import targets ;
+import toolset ;
+import type ;
 import utility ;
-import errors ;
+import xsltproc ;
+import virtual-target ;
 
 
-# Use to specify extra configuration paramters. These get translated
-# into a doxyfile which configures the building of the docs.
+# Use to specify extra configuration paramters. These get translated into a
+# doxyfile which configures the building of the docs.
 feature.feature doxygen:param : : free ;
 
 # Specify the "<xsl:param>boost.doxygen.header.prefix" XSLT option.
@@ -86,6 +85,7 @@
 
 type.register DOXYGEN_XML_IMAGES : doxygen-xml-images ;
 
+
 # Initialize the Doxygen module. Parameters are:
 # name: the name of the 'doxygen' executable. If not specified, the name
 # 'doxygen' will be used
@@ -132,16 +132,17 @@
     }
 }
 
-rule freeze-config ( )
+
+local rule freeze-config ( )
 {
     if ! $(.initialized)
     {
- errors.user-error "doxygen must be initialized before it can be used." ;
+ import errors ;
+ errors.user-error doxygen must be initialized before it can be used. ;
     }
     if ! $(.config-frozen)
     {
         .config-frozen = true ;
-
         if [ .is-cygwin ]
         {
             .is-cygwin = true ;
@@ -149,15 +150,18 @@
     }
 }
 
-rule modify-config ( )
+
+local rule modify-config ( )
 {
     if $(.config-frozen)
     {
+ import errors ;
         errors.user-error "Cannot change doxygen after it has been used." ;
     }
 }
 
-rule check-doxygen ( )
+
+local rule check-doxygen ( )
 {
     if --debug-configuration in [ modules.peek : ARGV ]
     {
@@ -176,25 +180,28 @@
             extra-paths = "C:\\Program Files" ;
         }
     }
- .doxygen = [ common.get-invocation-command doxygen :
- doxygen : $(.doxygen) : $(extra-paths) ] ;
+ .doxygen = [ common.get-invocation-command doxygen : doxygen : $(.doxygen) :
+ $(extra-paths) ] ;
 }
 
+
 rule name ( )
 {
     freeze-config ;
     return $(.doxygen) ;
 }
 
-rule .is-cygwin ( )
+
+local rule .is-cygwin ( )
 {
     if [ os.on-windows ]
     {
         local file = [ path.make [ modules.binding $(__name__) ] ] ;
- local dir = [ path.native
- [ path.join [ path.parent $(file) ] doxygen ] ] ;
- local command =
- "cd \"$(dir)\" && \"$(.doxygen)\" windows-paths-check.doxyfile 2>&1" ;
+ local dir = [ path.native [ path.join [ path.parent $(file) ] doxygen ]
+ ] ;
+ local command = cd \"$(dir)\" "&&" \"$(.doxygen)\"
+ windows-paths-check.doxyfile 2>&1 ;
+ command = $(command:J=" ") ;
         result = [ SHELL $(command) ] ;
         if [ MATCH "(Parsing file /)" : $(result) ]
         {
@@ -203,6 +210,7 @@
     }
 }
 
+
 # Runs Doxygen on the given Doxygen configuration file (the source) to generate
 # the Doxygen files. The output is dumped according to the settings in the
 # Doxygen configuration file, not according to the target! Because of this, we
@@ -272,18 +280,18 @@
 #
 rule headers-to-doxyfile ( target : sources * : properties * )
 {
- local text "# Generated by Boost.Build version 2" ;
+ local text = "# Generated by Boost.Build version 2" ;
 
     local output-dir ;
 
     # Translate <doxygen:param> into command line flags.
     for local param in [ feature.get-values <doxygen:param> : $(properties) ]
     {
- local namevalue = [ regex.match ([^=]*)=(.*) : $(param) ] ;
+ local namevalue = [ MATCH ([^=]*)=(.*) : $(param) ] ;
         if $(namevalue[1]) = OUTPUT_DIRECTORY
         {
- output-dir = [ translate-path
- [ utility.unquote $(namevalue[2]) ] ] ;
+ output-dir = [ translate-path [ utility.unquote $(namevalue[2]) ] ]
+ ;
             text += "OUTPUT_DIRECTORY = \"$(output-dir)\"" ;
         }
         else
@@ -298,7 +306,7 @@
         text += "OUTPUT_DIRECTORY = \"$(output-dir)\"" ;
     }
 
- local headers = ;
+ local headers ;
     for local header in $(sources:G=)
     {
         header = [ translate-path $(header) ] ;
@@ -322,33 +330,26 @@
     freeze-config ;
     if <doxygen.rmdir>on in $(properties)
     {
- local output-dir =
- [ path.make
- [ MATCH <doxygen:param>OUTPUT_DIRECTORY=\"?([^\"]*) :
- $(properties) ] ] ;
- local html-dir =
- [ path.make
- [ MATCH <doxygen:param>HTML_OUTPUT=(.*) :
- $(properties) ] ] ;
+ local output-dir = [ path.make [ MATCH
+ <doxygen:param>OUTPUT_DIRECTORY=\"?([^\"]*) : $(properties) ] ] ;
+ local html-dir = [ path.make [ MATCH <doxygen:param>HTML_OUTPUT=(.*) :
+ $(properties) ] ] ;
         if $(output-dir) && $(html-dir) &&
             [ path.glob $(output-dir) : $(html-dir) ]
         {
- HTMLDIR on $(target) =
- [ path.native [ path.join $(output-dir) $(html-dir) ] ] ;
+ HTMLDIR on $(target) = [ path.native [ path.join $(output-dir)
+ $(html-dir) ] ] ;
             rm-htmldir $(target) ;
         }
     }
     doxygen-action $(target) : $(source) ;
     NAME on $(target) = $(.doxygen) ;
     RM on $(target) = [ modules.peek common : RM ] ;
- *.XML on $(target) =
- [ path.native
- [ path.join
- [ path.make [ on $(target) return $(LOCATE) ] ]
- $(target:B:S=)
- *.xml ] ] ;
+ *.XML on $(target) = [ path.native [ path.join [ path.make [ on $(target)
+ return $(LOCATE) ] ] $(target:B:S=) *.xml ] ] ;
 }
 
+
 if [ os.name ] = NT
 {
     RMDIR = rmdir /s /q ;
@@ -363,26 +364,28 @@
     $(RMDIR) $(HTMLDIR)
 }
 
-# The rules below require Boost.Book stylesheets, so we need some code to check
+
+# The rules below require BoostBook stylesheets, so we need some code to check
 # that the boostbook module has actualy been initialized.
 #
 rule check-boostbook ( )
 {
     if ! [ modules.peek boostbook : .initialized ]
     {
- ECHO "error: the boostbook module is not initialized" ;
- ECHO "error: you've attempted to use the 'doxygen' toolset, " ;
- ECHO "error: which requires Boost.Book," ;
- ECHO "error: but never initialized Boost.Book." ;
- EXIT "error: Hint: add 'using boostbook ;' to your user-config.jam" ;
+ import errors ;
+ errors.user-error
+ : The boostbook module is not initialized you have attempted to use
+ : the 'doxygen' toolset, which requires BoostBook, but never
+ : initialized BoostBook.
+ : Hint: add 'using boostbook ;' to your user-config.jam. ;
     }
 }
 
 
 # Collect the set of Doxygen XML files into a single XML source file that can be
 # handled by an XSLT processor. The source is completely ignored (see
-# doxygen-action), because this action picks up the Doxygen XML index file
-# xml/index.xml. This is because we can not teach Doxygen to act like a NORMAL
+# doxygen-action), because this action picks up the Doxygen XML index file xml/
+# index.xml. This is because we can not teach Doxygen to act like a NORMAL
 # program and take a "-o output.xml" argument (grrrr). The target of the
 # collection will be a single Doxygen XML file.
 #
@@ -427,17 +430,16 @@
 }
 
 
-flags doxygen.xml-dir-to-boostbook OPTIONS <doxygen.doxproc.index>yes : --enable-index ;
-flags doxygen.xml-dir-to-boostbook ID <doxygen.doxproc.id> ;
-flags doxygen.xml-dir-to-boostbook TITLE <doxygen.doxproc.title> ;
+toolset.flags doxygen.xml-dir-to-boostbook OPTIONS <doxygen.doxproc.index>yes :
+ --enable-index ;
+toolset.flags doxygen.xml-dir-to-boostbook ID <doxygen.doxproc.id> ;
+toolset.flags doxygen.xml-dir-to-boostbook TITLE <doxygen.doxproc.title> ;
 
 
 rule xml-dir-to-boostbook ( target : source : properties * )
 {
     DOXPROC on $(target) = $(.doxproc) ;
-
     LOCATE on $(source:S=) = [ on $(source) return $(LOCATE) ] ;
-
     doxygen.doxproc $(target) : $(source:S=) ;
 }
 
@@ -469,23 +471,14 @@
 
 rule copy-latex-pngs ( target : source : requirements * )
 {
- local directory = [ path.native
- [ feature.get-values <doxygen:xml-imagedir> :
- $(requirements) ] ] ;
-
+ local directory = [ path.native [ feature.get-values <doxygen:xml-imagedir>
+ : $(requirements) ] ] ;
     local location = [ on $(target) return $(LOCATE) ] ;
 
- local pdf-location =
- [ path.native
- [ path.join
- [ path.make $(location) ]
- [ path.make $(directory) ] ] ] ;
- local html-location =
- [ path.native
- [ path.join
- .
- html
- [ path.make $(directory) ] ] ] ;
+ local pdf-location = [ path.native [ path.join [ path.make $(location) ]
+ [ path.make $(directory) ] ] ] ;
+ local html-location = [ path.native [ path.join . html [ path.make
+ $(directory) ] ] ] ;
 
     common.MkDir $(pdf-location) ;
     common.MkDir $(html-location) ;
@@ -515,12 +508,10 @@
     echo "Stamped" > "$(<)"
 }
 
-# building latex images for doxygen XML depends
-# on latex, dvips, and ps being in your PATH.
-# This is true for most Unix installs, but
-# not on Win32, where you will need to install
-# MkTex and Ghostscript and add these tools
-# to your path.
+
+# Building latex images for doxygen XML depends on latex, dvips, and gs being in
+# your PATH. This is true for most Unix installs, but not on Win32, where you
+# will need to install MkTex and Ghostscript and add these tools to your path.
 
 actions check-latex
 {
@@ -534,82 +525,99 @@
 
 if [ os.name ] = "NT"
 {
- actions check-gs
- {
- gswin32c -version >$(<)
- }
+ actions check-gs
+ {
+ gswin32c -version >$(<)
+ }
 }
 else
 {
- actions check-gs
- {
- gs -version >$(<)
- }
+ actions check-gs
+ {
+ gs -version >$(<)
+ }
 }
 
-rule check-tools ( )
+
+local rule check-tools-targets ( project )
 {
     if ! $(.check-tools-targets)
     {
         # Find the root project.
- local root-project = [ project.current ] ;
- root-project = [ $(root-project).project-module ] ;
- while
- [ project.attribute $(root-project) parent-module ] &&
- [ project.attribute $(root-project) parent-module ] != user-config
- {
- root-project =
- [ project.attribute $(root-project) parent-module ] ;
+ #
+ # This is a best effort attempt to avoid using different locations for
+ # storing *.check files depending on which project imported the doxygen
+ # toolset first. The files are stored in a location related to the
+ # project's root project. Note that this location may change depending
+ # on the folder the build was run from in case the build uses multiple
+ # related projects with their own Jamroot separate modules.
+ local project-module = [ $(project).project-module ] ;
+ local root-module = [ project.get-jamroot-module $(project-module) ] ;
+ if ! $(root-module)
+ {
+ import errors ;
+ if [ project.is-config-module $(project-module) ]
+ {
+ errors.user-error doxygen targets can not be declared in Boost
+ Build's configuration modules. ;
+ }
+ else
+ {
+ errors.user-error doxygen targets can not be declared in
+ standalone projects. : use a Jamfile/Jamroot project
+ instead. ;
+ }
         }
+ local root-project = [ project.target $(root-module) ] ;
 
- .latex.check = [ new file-target latex.check
- :
- : [ project.target $(root-project) ]
- : [ new action : doxygen.check-latex ]
- :
- ] ;
- .dvips.check = [ new file-target dvips.check
- :
- : [ project.target $(root-project) ]
- : [ new action : doxygen.check-dvips ]
- :
- ] ;
- .gs.check = [ new file-target gs.check
- :
- : [ project.target $(root-project) ]
- : [ new action : doxygen.check-gs ]
- :
- ] ;
- .check-tools-targets = $(.latex.check) $(.dvips.check) $(.gs.check) ;
+ local targets =
+ [ new file-target latex.check : : $(root-project) : [ new action :
+ doxygen.check-latex ] ]
+ [ new file-target dvips.check : : $(root-project) : [ new action :
+ doxygen.check-dvips ] ]
+ [ new file-target gs.check : : $(root-project) : [ new action :
+ doxygen.check-gs ] ] ;
+
+ for local target in $(targets)
+ {
+ .check-tools-targets += [ virtual-target.register $(target) ] ;
+ }
     }
     return $(.check-tools-targets) ;
 }
 
+
 project.initialize $(__name__) ;
 project doxygen ;
 
 class doxygen-check-tools-target-class : basic-target
 {
- import doxygen ;
     rule construct ( name : sources * : property-set )
     {
- return [ property-set.empty ] [ doxygen.check-tools ] ;
+ IMPORT doxygen : check-tools-targets : $(__name__) :
+ doxygen.check-tools-targets ;
+ return [ property-set.empty ] [ doxygen.check-tools-targets [ project ]
+ ] ;
     }
 }
 
-local project = [ project.current ] ;
 
-targets.main-target-alternative
- [ new doxygen-check-tools-target-class check-tools : $(project)
- : [ targets.main-target-sources : check-tools : no-renaming ]
- : [ targets.main-target-requirements : $(project) ]
- : [ targets.main-target-default-build : $(project) ]
- : [ targets.main-target-usage-requirements : $(project) ]
- ] ;
+# Declares a metatarget for collecting version information on different external
+# tools used in this module.
+#
+rule check-tools ( target )
+{
+ freeze-config ;
+ targets.create-metatarget doxygen-check-tools-target-class :
+ [ project.current ] : $(target) ;
+}
+
 
-# User-level rule to generate BoostBook XML from a set of headers via Doxygen.
+# User-level rule to generate HTML files or BoostBook XML from a set of headers
+# via Doxygen.
 #
-rule doxygen ( target : sources * : requirements * : default-build * : usage-requirements * )
+rule doxygen ( target : sources + : requirements * : default-build * :
+ usage-requirements * )
 {
     freeze-config ;
     local project = [ project.current ] ;
@@ -617,96 +625,103 @@
     if $(target:S) = .html
     {
         # Build an HTML directory from the sources.
- local html-location = [ feature.get-values <location> : $(requirements) ] ;
+ local html-location = [ feature.get-values <location> : $(requirements)
+ ] ;
         local output-dir ;
- if [ $(project).get build-dir ]
+ if [ $(project).get build-dir ]
         {
             # Explicitly specified build dir. Add html at the end.
- output-dir = [ path.join [ $(project).build-dir ] $(html-location:E=html) ] ;
+ output-dir = [ path.join [ $(project).build-dir ]
+ $(html-location:E=html) ] ;
         }
         else
         {
- # Trim 'bin' from implicit build dir, for no other reason that backward
- # compatibility.
- output-dir = [ path.join [ path.parent [ $(project).build-dir ] ]
- $(html-location:E=html) ] ;
+ # Trim 'bin' from implicit build dir, for no other reason than
+ # backward compatibility.
+ output-dir = [ path.join [ path.parent [ $(project).build-dir ] ]
+ $(html-location:E=html) ] ;
         }
- output-dir = [ path.root $(output-dir) [ path.pwd ] ] ;
+ output-dir = [ path.root $(output-dir) [ path.pwd ] ] ;
         local output-dir-native = [ path.native $(output-dir) ] ;
         requirements = [ property.change $(requirements) : <location> ] ;
 
- ## The doxygen configuration file.
- targets.main-target-alternative
- [ new typed-target $(target:S=.tag) : $(project) : DOXYFILE
- : [ targets.main-target-sources $(sources) : $(target:S=.tag) ]
- : [ targets.main-target-requirements $(requirements)
- <doxygen:param>GENERATE_HTML=YES
- <doxygen:param>GENERATE_XML=NO
- <doxygen:param>"OUTPUT_DIRECTORY=\"$(output-dir-native)\""
- <doxygen:param>HTML_OUTPUT=$(target:B)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ # The doxygen configuration file.
+ targets.create-typed-target DOXYFILE : $(project) : $(target:S=.tag)
+ : $(sources)
+ : $(requirements)
+ <doxygen:param>GENERATE_HTML=YES
+ <doxygen:param>GENERATE_XML=NO
+ <doxygen:param>"OUTPUT_DIRECTORY=\"$(output-dir-native)\""
+ <doxygen:param>HTML_OUTPUT=$(target:B)
+ : $(default-build) ;
         $(project).mark-target-as-explicit $(target:S=.tag) ;
 
- ## The html directory to generate by running doxygen.
- targets.main-target-alternative
- [ new typed-target $(target:S=.dir) : $(project) : DOXYGEN_HTML_MULTIFILE
- : $(target:S=.tag)
- : [ targets.main-target-requirements $(requirements)
- <doxygen:param>"OUTPUT_DIRECTORY=\"$(output-dir-native)\""
- <doxygen:param>HTML_OUTPUT=$(target:B)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ # The html directory to generate by running doxygen.
+ targets.create-typed-target DOXYGEN_HTML_MULTIFILE : $(project)
+ : $(target:S=.dir) # Name.
+ : $(target:S=.tag) # Sources.
+ : $(requirements)
+ <doxygen:param>"OUTPUT_DIRECTORY=\"$(output-dir-native)\""
+ <doxygen:param>HTML_OUTPUT=$(target:B)
+ : $(default-build) ;
         $(project).mark-target-as-explicit $(target:S=.dir) ;
 
- ## The redirect html file into the generated html.
- targets.main-target-alternative
- [ new typed-target $(target) : $(project) : DOXYGEN_HTML
- : $(target:S=.dir)
- : [ targets.main-target-requirements $(requirements)
- <location>$(output-dir)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ # The redirect html file into the generated html.
+ targets.create-typed-target DOXYGEN_HTML : $(project) : $(target)
+ : $(target:S=.dir) # Sources.
+ : $(requirements) <location>$(output-dir)
+ : $(default-build) ;
     }
     else
     {
         # Build a BoostBook XML file from the sources.
- local location-xml = [ feature.get-values <location> : $(requirements) ] ;
+ local location-xml = [ feature.get-values <location> : $(requirements) ]
+ ;
         requirements = [ property.change $(requirements) : <location> ] ;
         local target-xml = $(target:B=$(target:B)-xml) ;
 
- # Check whether we need to build images
- local images-location =
- [ feature.get-values <doxygen:xml-imagedir> : $(requirements) ] ;
+ # Check whether we need to build images.
+ local images-location = [ feature.get-values <doxygen:xml-imagedir> :
+ $(requirements) ] ;
         if $(images-location)
         {
- doxygen $(target).doxygen-xml-images.html : $(sources)
- : $(requirements)
- <doxygen.rmdir>on
- <doxygen:param>QUIET=YES
- <doxygen:param>WARNINGS=NO
- <doxygen:param>WARN_IF_UNDOCUMENTED=NO
- <dependency>/doxygen//check-tools ;
- $(project).mark-target-as-explicit
- $(target).doxygen-xml-images.html ;
-
- targets.main-target-alternative
- [ new typed-target $(target).doxygen-xml-images
- : $(project) : DOXYGEN_XML_IMAGES
- : $(target).doxygen-xml-images.html
- : [ targets.main-target-requirements $(requirements)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build)
- : $(project) ]
- ] ;
+ # Prepare a metatarget for collecting used external tool version
+ # information. We use only one such metatarget as they always
+ # produce the same files and we do not want to deal with multiple
+ # metatargets having matching names, causing 'ambiguous variants'
+ # errors.
+ if ! $(.check-tools)
+ {
+ # FIXME: Since we have the check-tools target object reference,
+ # see how we can use that instead of having to construct a valid
+ # target reference string for use in <dependency> property
+ # values.
+ local project-id = --doxygen.check-tools-project-- ;
+ local target-id = --doxygen.check-tools-- ;
+ local pm = [ $(project).project-module ] ;
+ project.register-id $(project-id) : $(pm) ;
+ check-tools $(target-id) ;
+ .check-tools = /$(project-id)//$(target-id) ;
+ }
 
- $(project).mark-target-as-explicit
- $(target).doxygen-xml-images ;
+ doxygen $(target).doxygen-xml-images.html : $(sources) :
+ $(requirements)
+ <doxygen.rmdir>on
+ <doxygen:param>QUIET=YES
+ <doxygen:param>WARNINGS=NO
+ <doxygen:param>WARN_IF_UNDOCUMENTED=NO
+ <dependency>$(.check-tools) ;
+ $(project).mark-target-as-explicit $(target).doxygen-xml-images.html
+ ;
+
+ targets.create-typed-target DOXYGEN_XML_IMAGES : $(project)
+ : $(target).doxygen-xml-images # Name.
+ : $(target).doxygen-xml-images.html # Sources.
+ : $(requirements)
+ : $(default-build) ;
+ $(project).mark-target-as-explicit $(target).doxygen-xml-images ;
 
- if ! [ regex.match "^(.*/)$" : $(images-location) ]
+ if ! [ MATCH (/)$ : $(images-location) ]
             {
                 images-location = $(images-location)/ ;
             }
@@ -716,61 +731,45 @@
                 <xsl:param>boost.doxygen.formuladir=$(images-location) ;
         }
 
- ## The doxygen configuration file.
- targets.main-target-alternative
- [ new typed-target $(target-xml:S=.tag) : $(project) : DOXYFILE
- : [ targets.main-target-sources $(sources) : $(target-xml:S=.tag) ]
- : [ targets.main-target-requirements $(requirements)
- <doxygen:param>GENERATE_HTML=NO
- <doxygen:param>GENERATE_XML=YES
- <doxygen:param>XML_OUTPUT=$(target-xml)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ # The doxygen configuration file.
+ targets.create-typed-target DOXYFILE : $(project) : $(target-xml:S=.tag)
+ : $(sources)
+ : $(requirements)
+ <doxygen:param>GENERATE_HTML=NO
+ <doxygen:param>GENERATE_XML=YES
+ <doxygen:param>XML_OUTPUT=$(target-xml)
+ : $(default-build) ;
         $(project).mark-target-as-explicit $(target-xml:S=.tag) ;
 
- ## The Doxygen XML directory of the processed source files.
- targets.main-target-alternative
- [ new typed-target $(target-xml:S=.dir) : $(project) : DOXYGEN_XML_MULTIFILE
- : $(target-xml:S=.tag)
- : [ targets.main-target-requirements $(requirements)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ # The Doxygen XML directory for the processed source files.
+ targets.create-typed-target DOXYGEN_XML_MULTIFILE : $(project)
+ : $(target-xml:S=.dir) # Name.
+ : $(target-xml:S=.tag) # Sources.
+ : $(requirements)
+ : $(default-build) ;
         $(project).mark-target-as-explicit $(target-xml:S=.dir) ;
 
- ## The resulting BoostBook file is generated by the processor tool. The
- ## tool can be either the xsltproc plus accompanying XSL scripts. Or it
- ## can be the python doxproc.py script.
- targets.main-target-alternative
- [ new typed-target $(target-xml) : $(project) : BOOSTBOOK
- : $(target-xml:S=.dir)
- : [ targets.main-target-requirements $(requirements)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ # The resulting BoostBook file is generated by the processor tool. The
+ # tool can be either the xsltproc plus accompanying XSL scripts. Or it
+ # can be the python doxproc.py script.
+ targets.create-typed-target BOOSTBOOK : $(project) : $(target-xml)
+ : $(target-xml:S=.dir) # Sources.
+ : $(requirements)
+ : $(default-build) ;
         $(project).mark-target-as-explicit $(target-xml) ;
 
- targets.main-target-alternative
- [ new install-target-class $(target:S=.xml) : $(project)
- : $(target-xml)
- : [ targets.main-target-requirements $(requirements)
- <location>$(location-xml:E=.)
- <name>$(target:S=.xml)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ stage $(target:S=.xml) # Name.
+ : $(target-xml) # Sources.
+ : $(requirements)
+ <location>$(location-xml:E=.)
+ <name>$(target:S=.xml)
+ : $(default-build) ;
         $(project).mark-target-as-explicit $(target:S=.xml) ;
 
- targets.main-target-alternative
- [ new alias-target-class $(target) : $(project)
- :
- : [ targets.main-target-requirements $(requirements)
- : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- : [ targets.main-target-usage-requirements $(usage-requirements)
- <dependency>$(target:S=.xml)
- : $(project) ]
- ] ;
+ # TODO: See why this alias target is used here instead of simply naming
+ # the previous stage target $(target) and having it specify the alias
+ # target's usage requirements directly.
+ alias $(target) : : $(requirements) : $(default-build) :
+ $(usage-requirements) <dependency>$(target:S=.xml) ;
     }
 }

Modified: branches/release/tools/build/v2/tools/gcc.py
==============================================================================
--- branches/release/tools/build/v2/tools/gcc.py (original)
+++ branches/release/tools/build/v2/tools/gcc.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -282,7 +282,9 @@
 
 flags('gcc.compile', 'OPTIONS', ['<debug-symbols>on'], ['-g'])
 flags('gcc.compile', 'OPTIONS', ['<profiling>on'], ['-pg'])
-flags('gcc.compile', 'OPTIONS', ['<rtti>off'], ['-fno-rtti'])
+
+flags('gcc.compile.c++', 'OPTIONS', ['<rtti>off'], ['-fno-rtti'])
+flags('gcc.compile.c++', 'OPTIONS', ['<exception-handling>off'], ['-fno-exceptions'])
 
 # On cygwin and mingw, gcc generates position independent code by default, and
 # warns if -fPIC is specified. This might not be the right way of checking if

Modified: branches/release/tools/build/v2/tools/make.jam
==============================================================================
--- branches/release/tools/build/v2/tools/make.jam (original)
+++ branches/release/tools/build/v2/tools/make.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -3,23 +3,22 @@
 # Copyright 2006 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
-# This module defines the 'make' main target rule.
+# This module defines the 'make' main target rule.
 
 import "class" : new ;
-import errors : error ;
 import project ;
-import property ;
 import property-set ;
-import regex ;
 import targets ;
 
 
 class make-target-class : basic-target
 {
- import type regex virtual-target ;
     import "class" : new ;
+ import type ;
+ import virtual-target ;
 
     rule __init__ ( name : project : sources * : requirements *
         : default-build * : usage-requirements * )
@@ -48,8 +47,6 @@
 rule make ( target-name : sources * : generating-rule + : requirements * :
     usage-requirements * )
 {
- local project = [ project.current ] ;
-
     # The '@' sign causes the feature.jam module to qualify rule name with the
     # module name of current project, if needed.
     local m = [ MATCH ^(@).* : $(generating-rule) ] ;
@@ -57,15 +54,9 @@
     {
         generating-rule = @$(generating-rule) ;
     }
- requirements += <action>$(generating-rule) ;
-
- targets.main-target-alternative
- [ new make-target-class $(target-name) : $(project)
- : [ targets.main-target-sources $(sources) : $(target-name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build : $(project) ]
- : [ targets.main-target-usage-requirements $(usage-requirements) :
- $(project) ] ] ;
+ targets.create-metatarget make-target-class : [ project.current ] :
+ $(target-name) : $(sources) : $(requirements) <action>$(generating-rule)
+ : : $(usage-requirements) ;
 }
 
 

Modified: branches/release/tools/build/v2/tools/message.jam
==============================================================================
--- branches/release/tools/build/v2/tools/message.jam (original)
+++ branches/release/tools/build/v2/tools/message.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -12,16 +12,17 @@
 
 class message-target-class : basic-target
 {
- rule __init__ ( name-and-dir : project : * )
+ rule set-message ( * )
     {
- basic-target.__init__ $(name-and-dir) : $(project) ;
+ self.1 = $(1) ;
+ self.2 = $(2) ;
         self.3 = $(3) ;
         self.4 = $(4) ;
         self.5 = $(5) ;
         self.6 = $(6) ;
         self.7 = $(7) ;
         self.8 = $(8) ;
- self.9 = $(9) ;
+ self.9 = $(9) ;
         self.built = ;
     }
     
@@ -29,7 +30,7 @@
     {
         if ! $(self.built)
         {
- for i in 3 4 5 6 7 8 9
+ for i in 1 2 3 4 5 6 7 8 9
             {
                 if $(self.$(i))
                 {
@@ -48,8 +49,14 @@
 {
     local project = [ project.current ] ;
 
- targets.main-target-alternative
- [ new message-target-class $(name) : $(project)
- : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) ] ;
+ local result = [ targets.main-target-alternative
+ [ new message-target-class $(name) : $(project)
+ : [ targets.main-target-sources : $(name) ]
+ : [ targets.main-target-requirements : $(project) ]
+ : [ targets.main-target-default-build : $(project) ]
+ : [ targets.main-target-usage-requirements : $(project) ]
+ ] ] ;
+ $(result).set-message $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ return $(result) ;
 }
-IMPORT $(__name__) : message : : message ;
\ No newline at end of file
+IMPORT $(__name__) : message : : message ;

Modified: branches/release/tools/build/v2/tools/msvc.jam
==============================================================================
--- branches/release/tools/build/v2/tools/msvc.jam (original)
+++ branches/release/tools/build/v2/tools/msvc.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,13 +1,13 @@
-# Copyright (c) 2003 David Abrahams.
-# Copyright (c) 2005 Vladimir Prus.
-# Copyright (c) 2005 Alexey Pakhunov.
-# Copyright (c) 2006 Bojan Resnik.
-# Copyright (c) 2006 Ilya Sokolov.
+# Copyright (c) 2003 David Abrahams
+# Copyright (c) 2005 Vladimir Prus
+# Copyright (c) 2005 Alexey Pakhunov
+# Copyright (c) 2006 Bojan Resnik
+# Copyright (c) 2006 Ilya Sokolov
 # Copyright (c) 2007 Rene Rivera
 # Copyright (c) 2008 Jurko Gospodnetic
 #
-# Use, modification and distribution is subject to the Boost Software
-# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
+# 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)
 
 ################################################################################
@@ -23,7 +23,6 @@
 
 import "class" : new ;
 import common ;
-import errors ;
 import feature ;
 import generators ;
 import mc ;
@@ -42,6 +41,7 @@
 
 type.register PDB : pdb ;
 
+
 ################################################################################
 #
 # Public rules.
@@ -126,6 +126,7 @@
     # <setup-amd64>
     # <setup-i386>
     # <setup-ia64>
+ # <setup-arm>
     # Platform specific setup command to invoke before running any of the
     # msvc tools used when builing a target for a specific platform, e.g.
     # when building a 32 or 64 bit executable.
@@ -151,6 +152,7 @@
         case "all" :
             if $(options)
             {
+ import errors ;
                 errors.error "MSVC toolset configuration: options should be"
                     "empty when '$(version)' is specified." ;
             }
@@ -260,10 +262,11 @@
         toolset.flags $(toolset).link LINKFLAGS $(conditions)/$(.cpu-arch-amd64) : /MACHINE:X64 ;
         toolset.flags $(toolset).link LINKFLAGS $(conditions)/$(.cpu-arch-i386) : /MACHINE:X86 ;
         toolset.flags $(toolset).link LINKFLAGS $(conditions)/$(.cpu-arch-ia64) : /MACHINE:IA64 ;
-
+ toolset.flags $(toolset).link LINKFLAGS $(conditions)/$(.cpu-arch-arm) : /MACHINE:ARM ;
+
         # Make sure that manifest will be generated even if there is no
         # dependencies to put there.
- toolset.flags $(toolset).link LINKFLAGS $(conditions)/<embed-manifest>off : /MANIFEST ;
+ toolset.flags $(toolset).link LINKFLAGS $(conditions) : /MANIFEST ;
     }
     toolset.pop-checking-for-flags-module ;
 }
@@ -355,15 +358,19 @@
 #
 # WARNING: Synchronize any changes this in action with intel-win
 #
-# Notes regarding PDB generation, for when we use <debug-symbols>on/<debug-store>database
-#
-# 1. PDB_CFLAG is only set for <debug-symbols>on/<debug-store>database, ensuring that the /Fd flag is dropped if PDB_CFLAG is empty
+# Notes regarding PDB generation, for when we use
+# <debug-symbols>on/<debug-store>database:
 #
-# 2. When compiling executables's source files, PDB_NAME is set on a per-source file basis by rule compile-c-c++.
-# The linker will pull these into the executable's PDB
+# 1. PDB_CFLAG is only set for <debug-symbols>on/<debug-store>database, ensuring
+# that the /Fd flag is dropped if PDB_CFLAG is empty.
 #
-# 3. When compiling library's source files, PDB_NAME is updated to <libname>.pdb for each source file by rule archive,
-# as in this case the compiler must be used to create a single PDB for our library.
+# 2. When compiling executables's source files, PDB_NAME is set on a per-source
+# file basis by rule compile-c-c++. The linker will pull these into the
+# executable's PDB.
+#
+# 3. When compiling library's source files, PDB_NAME is updated to <libname>.pdb
+# for each source file by rule archive, as in this case compiler must be used
+# to create a single PDB for our library.
 #
 actions compile-c-c++ bind PDB_NAME
 {
@@ -379,7 +386,8 @@
 {
     DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_HEADER) ] ;
     DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_FILE) ] ;
- PDB_NAME on $(<) = $(<:S=.pdb) ;
+ PDB_NAME on $(<) = $(<[1]:S=.pdb) ;
+ LOCATE on $(<[1]:S=.pdb) = [ on $(<[1]) return $(LOCATE) ] ;
 }
 
 rule preprocess-c-c++ ( targets + : sources * )
@@ -387,6 +395,7 @@
     DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_HEADER) ] ;
     DEPENDS $(<[1]) : [ on $(<[1]) return $(PCH_FILE) ] ;
     PDB_NAME on $(<) = $(<:S=.pdb) ;
+ LOCATE on $(<[1]:S=.pdb) = [ on $(<[1]) return $(LOCATE) ] ;
 }
 
 # Action for running the C/C++ compiler using precompiled headers. In addition
@@ -539,22 +548,25 @@
     actions manifest.dll
     {
         if test -e "$(<[1]).manifest"; then
- $(.MT) -manifest "$(<[1]:W).manifest" "-outputresource:$(<[1]:W);2"
+ $(.MT) -manifest "$(<[1]:W).manifest" "-outputresource:$(<[1]:W);2"
         fi
     }
 }
 
-# this rule sets up the pdb file that will be used when generating static
-# libraries and the debug-store option is database, so that the compiler
-# puts all debug info into a single .pdb file named after the library
+# This rule sets up the pdb file that will be used when generating static
+# libraries and the debug-store option is database, so that the compiler puts
+# all the debug info into a single .pdb file named after the library.
 #
-# Poking at source targets this way is probably not clean, but it's the
+# Poking at source targets this way is probably not clean, but it is the
 # easiest approach.
+#
 rule archive ( targets + : sources * : properties * )
 {
- PDB_NAME on $(>) = $(<:S=.pdb) ;
+ PDB_NAME on $(>) = $(<[1]:S=.pdb) ;
+ LOCATE on $(<[1]:S=.pdb) = [ on $(<[1]) return $(LOCATE) ] ;
 }
 
+
 ################################################################################
 #
 # Classes.
@@ -586,6 +598,7 @@
 
         if ! $(pch-header)
         {
+ import errors : user-error : errors.user-error ;
             errors.user-error "can not build pch without pch-header" ;
         }
 
@@ -699,6 +712,7 @@
         # identical sets of options are used.
         if $(options) && ( $(options) != [ $(.versions).get $(version) : options ] )
         {
+ import errors ;
             errors.error "MSVC toolset configuration: Toolset version"
                 "'$(version)' already configured." ;
         }
@@ -774,7 +788,7 @@
 
         local below-8.0 = [ MATCH ^([67]\\.) : $(version) ] ;
 
- local cpu = i386 amd64 ia64 ;
+ local cpu = i386 amd64 ia64 arm ;
         if $(below-8.0)
         {
             cpu = i386 ;
@@ -783,6 +797,7 @@
         local setup-amd64 ;
         local setup-i386 ;
         local setup-ia64 ;
+ local setup-arm ;
 
         if $(command)
         {
@@ -836,6 +851,7 @@
             local default-setup-amd64 = vcvarsx86_amd64.bat ;
             local default-setup-i386 = vcvars32.bat ;
             local default-setup-ia64 = vcvarsx86_ia64.bat ;
+ local default-setup-arm = vcvarsx86_arm.bat ;
 
             # http://msdn2.microsoft.com/en-us/library/x4d2c09s(VS.80).aspx and
             # http://msdn2.microsoft.com/en-us/library/x4d2c09s(vs.90).aspx
@@ -844,6 +860,7 @@
             local default-global-setup-options-amd64 = x86_amd64 ;
             local default-global-setup-options-i386 = x86 ;
             local default-global-setup-options-ia64 = x86_ia64 ;
+ local default-global-setup-options-arm = x86_arm ;
 
             # When using 64-bit Windows, and targeting 64-bit, it is possible to
             # use a native 64-bit compiler, selected by the "amd64" & "ia64"
@@ -925,6 +942,7 @@
         local default-assembler-amd64 = ml64 ;
         local default-assembler-i386 = "ml -coff" ;
         local default-assembler-ia64 = ias ;
+ local default-assembler-ia64 = armasm ;
 
         assembler = [ feature.get-values <assembler> : $(options) ] ;
 
@@ -936,8 +954,9 @@
 
         manifest-tool = [ feature.get-values <manifest-tool> : $(options) ] ;
         manifest-tool ?= mt ;
-
- local cc-filter = [ feature.get-values <compiler-filter> : $(options) ] ;
+
+ local cc-filter = [ feature.get-values <compiler-filter> : $(options) ]
+ ;
 
         for local c in $(cpu)
         {
@@ -1063,16 +1082,19 @@
         {
             local name-main = [ $(result[0]).name ] ;
             local action = [ $(result[0]).action ] ;
-
+
             if [ $(property-set).get <debug-symbols> ] = "on"
- {
- # We force exact name on PDB. The reason is tagging -- the tag rule may
- # reasonably special case some target types, like SHARED_LIB. The tag rule
- # will not catch PDB, and it cannot even easily figure if PDB is paired with
- # SHARED_LIB or EXE or something else. Because PDB always get the
- # same name as the main target, with .pdb as extension, just force it.
- local target = [ class.new file-target $(name-main:S=.pdb) exact : PDB : $(project) : $(action) ] ;
- local registered-target = [ virtual-target.register $(target) ] ;
+ {
+ # We force the exact name on PDB. The reason is tagging -- the
+ # tag rule may reasonably special case some target types, like
+ # SHARED_LIB. The tag rule will not catch PDBs, and it cannot
+ # even easily figure out if a PDB is paired with a SHARED_LIB,
+ # EXE or something else. Because PDBs always get the same name
+ # as the main target, with .pdb as extension, just force it.
+ local target = [ class.new file-target $(name-main:S=.pdb) exact
+ : PDB : $(project) : $(action) ] ;
+ local registered-target = [ virtual-target.register $(target) ]
+ ;
                 if $(target) != $(registered-target)
                 {
                     $(action).replace-targets $(target) : $(registered-target) ;
@@ -1082,11 +1104,14 @@
 
             if [ $(property-set).get <embed-manifest> ] = "off"
             {
- # Manifest is evil target. It has .manifest appened to the name of
- # main target, including extension. E.g. a.exe.manifest. We use 'exact'
- # name because to achieve this effect.
- local target = [ class.new file-target $(name-main).manifest exact : MANIFEST : $(project) : $(action) ] ;
- local registered-target = [ virtual-target.register $(target) ] ;
+ # Manifest is an evil target. It has .manifest appened to the
+ # name of the main target, including extension, e.g.
+ # a.exe.manifest. We use the 'exact' name to achieve this
+ # effect.
+ local target = [ class.new file-target $(name-main).manifest
+ exact : MANIFEST : $(project) : $(action) ] ;
+ local registered-target = [ virtual-target.register $(target) ]
+ ;
                 if $(target) != $(registered-target)
                 {
                     $(action).replace-targets $(target) : $(registered-target) ;
@@ -1099,7 +1124,6 @@
 }
 
 
-
 # Unsafe worker rule for the register-toolset() rule. Must not be called
 # multiple times.
 #
@@ -1131,10 +1155,11 @@
         # TODO: Is it possible to combine these? Make the generators
         # non-composing so that they do not convert each source into a separate
         # .rsp file.
- generators.register [ new msvc-linking-generator
- msvc.link : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE : <toolset>msvc ] ;
- generators.register [ new msvc-linking-generator
- msvc.link.dll : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB : <toolset>msvc ] ;
+ generators.register [ new msvc-linking-generator msvc.link :
+ OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE : <toolset>msvc ] ;
+ generators.register [ new msvc-linking-generator msvc.link.dll :
+ OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB :
+ <toolset>msvc ] ;
 
         generators.register-archiver msvc.archive : OBJ : STATIC_LIB : <toolset>msvc ;
         generators.register-c-compiler msvc.compile.c++ : CPP : OBJ : <toolset>msvc ;
@@ -1288,7 +1313,8 @@
         {
             if $(.debug-configuration)
             {
- ECHO "notice: [msvc-cfg] msvc-$(version) detected, command: '$(command)'" ;
+ ECHO notice: [msvc-cfg] msvc-$(version) detected, command:
+ '$(command)' ;
             }
 
             $(.versions).register $(version) ;
@@ -1335,6 +1361,9 @@
     <architecture>ia64/<address-model>
     <architecture>ia64/<address-model>64 ;
 
+.cpu-arch-arm =
+ <architecture>arm/<address-model>32 ;
+
 
 # Supported CPU types (only Itanium optimization options are supported from
 # VC++ 2005 on). See
@@ -1356,7 +1385,8 @@
 
 
 # Known toolset versions, in order of preference.
-.known-versions = 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ;
+.known-versions = 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1
+ 7.1toolkit 7.0 6.0 ;
 
 # Version aliases.
 .version-alias-6 = 6.0 ;

Modified: branches/release/tools/build/v2/tools/msvc.py
==============================================================================
--- branches/release/tools/build/v2/tools/msvc.py (original)
+++ branches/release/tools/build/v2/tools/msvc.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -207,7 +207,7 @@
         
         # Make sure that manifest will be generated even if there is no
         # dependencies to put there.
- toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions,["<embed-manifest>off"]), ['/MANIFEST'])
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', conditions, ['/MANIFEST'])
 
 
 # Registers this toolset including all of its flags, features & generators. Does

Modified: branches/release/tools/build/v2/tools/notfile.jam
==============================================================================
--- branches/release/tools/build/v2/tools/notfile.jam (original)
+++ branches/release/tools/build/v2/tools/notfile.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,8 +1,7 @@
-# Copyright (c) 2005 Vladimir Prus.
-#
-# Use, modification and distribution is subject to the Boost Software
-# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
-# http://www.boost.org/LICENSE_1_0.txt)
+# Copyright (c) 2005 Vladimir Prus.
+# 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 "class" : new ;
 import generators ;
@@ -19,28 +18,26 @@
 {
     rule __init__ ( * : * )
     {
- generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
+ generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8)
+ : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) :
+ $(17) : $(18) : $(19) ;
     }
 
     rule run ( project name ? : property-set : sources * : multiple ? )
     {
         local action ;
         local action-name = [ $(property-set).get <action> ] ;
-
         local m = [ MATCH ^@(.*) : $(action-name) ] ;
-
         if $(m)
         {
- action = [ new action $(sources) : $(m[1])
- : $(property-set) ] ;
+ action = [ new action $(sources) : $(m[1]) : $(property-set) ] ;
         }
         else
         {
- action = [ new action $(sources) : notfile.run
- : $(property-set) ] ;
+ action = [ new action $(sources) : notfile.run : $(property-set) ] ;
         }
- return [ virtual-target.register
- [ new notfile-target $(name) : $(project) : $(action) ] ] ;
+ local t = [ new notfile-target $(name) : $(project) : $(action) ] ;
+ return [ virtual-target.register $(t) ] ;
     }
 }
 
@@ -57,18 +54,12 @@
 }
 
 
-rule notfile ( target-name : action + : sources * : requirements * : default-build * )
+rule notfile ( target-name : action + : sources * : requirements * :
+ default-build * )
 {
- local project = [ project.current ] ;
-
- requirements += <action>$(action) ;
-
- targets.main-target-alternative
- [ new typed-target $(target-name) : $(project) : NOTFILE_MAIN
- : [ targets.main-target-sources $(sources) : $(target-name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ targets.create-typed-target NOTFILE_MAIN : [ project.current ] :
+ $(target-name) : $(sources) : $(requirements) <action>$(action) :
+ $(default-build) ;
 }
 
 IMPORT $(__name__) : notfile : : notfile ;

Modified: branches/release/tools/build/v2/tools/pathscale.jam
==============================================================================
--- branches/release/tools/build/v2/tools/pathscale.jam (original)
+++ branches/release/tools/build/v2/tools/pathscale.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -8,6 +8,7 @@
 import toolset : flags ;
 import feature ;
 import type ;
+import os ;
 import common ;
 import fortran ;
 
@@ -54,6 +55,15 @@
 
   # always link lib rt to resolve clock_gettime()
   flags pathscale.link FINDLIBS-SA : rt : unchecked ;
+
+ switch [ os.name ]
+ {
+ case SOLARIS :
+ toolset.flags pathscale.link RPATH_OPTION $(condition) : -Wl,-R, -Wl, : unchecked ;
+
+ case * : # GNU
+ toolset.flags pathscale.link RPATH_OPTION $(condition) : -Wl,-rpath= : unchecked ;
+ }
 }
 
 # Declare generators
@@ -146,7 +156,7 @@
 
 actions link bind LIBRARIES
 {
- "$(CONFIG_COMMAND)" $(OPTIONS) $(USER_OPTIONS) -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" -o "$(<)" "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-SA) -l$(FINDLIBS-ST)
+ "$(CONFIG_COMMAND)" $(OPTIONS) $(USER_OPTIONS) -L"$(LINKPATH)" $(RPATH_OPTION:E=-Wl,-rpath=)"$(RPATH)" -o "$(<)" "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-SA) -l$(FINDLIBS-ST)
 }
 
 # Slight mods for dlls
@@ -157,7 +167,7 @@
 
 actions link.dll bind LIBRARIES
 {
- "$(CONFIG_COMMAND)" $(OPTIONS) $(USER_OPTIONS) -L"$(LINKPATH)" -Wl,$(RPATH_OPTION:E=-R)$(SPACE)-Wl,"$(RPATH)" -o "$(<)" -Wl,-soname$(SPACE)-Wl,$(<[1]:D=) -shared "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-SA) -l$(FINDLIBS-ST)
+ "$(CONFIG_COMMAND)" $(OPTIONS) $(USER_OPTIONS) -L"$(LINKPATH)" $(RPATH_OPTION:E=-Wl,-rpath=)"$(RPATH)" -o "$(<)" -Wl,-soname$(SPACE)-Wl,$(<[1]:D=) -shared "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-SA) -l$(FINDLIBS-ST)
 }
 
 # Declare action for creating static libraries

Modified: branches/release/tools/build/v2/tools/pgi.jam
==============================================================================
--- branches/release/tools/build/v2/tools/pgi.jam (original)
+++ branches/release/tools/build/v2/tools/pgi.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -29,7 +29,7 @@
 
   common.handle-options pgi : $(condition) : $(l_command) : $(options) ;
     
- command_c = $(command_c[1--2]) $(l_command[-1]:B=cc) ;
+ command_c = $(command_c[1--2]) $(l_command[-1]:B=pgcc) ;
 
   toolset.flags pgi CONFIG_C_COMMAND $(condition) : $(command_c) ;
 

Modified: branches/release/tools/build/v2/tools/python.jam
==============================================================================
--- branches/release/tools/build/v2/tools/python.jam (original)
+++ branches/release/tools/build/v2/tools/python.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -34,7 +34,6 @@
 import feature ;
 import set ;
 import builtin ;
-import version ;
 
 
 # Make this module a project.
@@ -477,14 +476,6 @@
         }
 
         # Invoke Python and ask it for all those values.
- if [ version.check-jam-version 3 1 17 ] || ( [ os.name ] != NT )
- {
- # Prior to version 3.1.17 Boost Jam's SHELL command did not support
- # quoted commands correctly on Windows. This means that on that
- # platform we do not support using a Python command interpreter
- # executable whose path contains a space character.
- python-cmd = \"$(python-cmd)\" ;
- }
         local full-cmd =
             $(python-cmd)" -c \"from sys import *; print('"$(format:J=\\n)"' % ("$(exprs:J=,)"))\"" ;
 
@@ -654,7 +645,7 @@
 
         case aix : return <library>pthread <library>dl ;
 
- case * : return <library>pthread <library>dl
+ case * : return <library>pthread <library>dl
             <toolset>gcc:<library>util <toolset-intel:platform>linux:<library>util ;
     }
 }
@@ -855,7 +846,7 @@
         }
         target-requirements += <python>$(version:E=default) ;
     }
-
+
     target-requirements += <target-os>$(target-os) ;
 
     # See if we can find a framework directory on darwin.
@@ -1098,7 +1089,7 @@
         local pyversion = [ $(property-set).get <python> ] ;
         local python ;
         local other-pythons ;
-
+
         # Make new target that converting Python source by 2to3 when running with Python 3.
         local rule make-2to3-source ( source )
         {

Modified: branches/release/tools/build/v2/tools/qcc.jam
==============================================================================
--- branches/release/tools/build/v2/tools/qcc.jam (original)
+++ branches/release/tools/build/v2/tools/qcc.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -214,10 +214,12 @@
 # The 'c' letter suppresses warnings in case the archive does not exists yet.
 # That warning is produced only on some platforms, for whatever reasons.
 #
+# Use qcc driver to create archive, see
+# http://www.qnx.com/developers/docs/6.3.2/neutrino/utilities/q/qcc.html
 actions piecemeal archive
 {
     $(RM) "$(<)"
- ar rc "$(<)" "$(>)"
+ "$(CONFIG_COMMAND)" -A "$(<)" "$(>)"
 }
 
 

Modified: branches/release/tools/build/v2/tools/qt4.jam
==============================================================================
--- branches/release/tools/build/v2/tools/qt4.jam (original)
+++ branches/release/tools/build/v2/tools/qt4.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -316,13 +316,19 @@
    # Setup common pre-built Qt.
    # Special setup for QtCore on which everything depends
    {
+ local link = [ feature.get-values link : $(condition) ] ;
+
        local usage-requirements =
            <include>$(.incprefix)
            <library-path>$(.libprefix)
- <dll-path>$(.libprefix)
            <threading>multi
            <allow>qt4 ;
 
+ if $(link) in shared
+ {
+ usage-requirements += <dll-path>$(.libprefix) ;
+ }
+
        local suffix ;
 
        # Since Qt-4.2, debug versions on unix have to be built
@@ -342,8 +348,11 @@
        {
            .have_separate_debug = TRUE ;
 
- # On NT, the libs have "4" suffix, and "d" suffix in debug builds.
- .suffix_version = "4" ;
+ # On NT, the shared libs have "4" suffix, and "d" suffix in debug builds.
+ if $(link) in shared
+ {
+ .suffix_version = "4" ;
+ }
            .suffix_debug = "d" ;
 
            # On Windows we must link against the qtmain library

Modified: branches/release/tools/build/v2/tools/rc.jam
==============================================================================
--- branches/release/tools/build/v2/tools/rc.jam (original)
+++ branches/release/tools/build/v2/tools/rc.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,19 +2,18 @@
 # distribute this software is granted provided this copyright notice appears in
 # all copies. This software is provided "as is" without express or implied
 # warranty, and with no claim as to its suitability for any purpose.
-#
+#
 # Copyright (c) 2006 Rene Rivera.
 #
 # Use, modification and distribution is subject to the Boost Software
 # License Version 1.0. (See accompanying file LICENSE_1_0.txt or
 # http://www.boost.org/LICENSE_1_0.txt)
 
-import type ;
 import generators ;
 import feature ;
-import errors ;
 import scanner ;
 import toolset : flags ;
+import type ;
 
 if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
 {
@@ -35,9 +34,9 @@
 #
 # Even though the arguments are all optional, only when a command, condition,
 # and at minimum the rc-type option are given will the command be configured.
-# This is so that callers don't have to check auto-configuration values
-# before calling this. And still get the functionality of build failures when
-# the resource compiler can't be found.
+# This is so that callers don't have to check auto-configuration values before
+# calling this. And still get the functionality of build failures when the
+# resource compiler can not be found.
 #
 rule configure ( command ? : condition ? : options * )
 {
@@ -78,28 +77,29 @@
     as /dev/null -o "$(<)"
 }
 
-# Since it's a common practice to write
-# exe hello : hello.cpp hello.rc
-# we change the name of object created from RC file, to
-# avoid conflict with hello.cpp.
-# The reason we generate OBJ and not RES, is that gcc does not
-# seem to like RES files, but works OK with OBJ.
-# See http://article.gmane.org/gmane.comp.lib.boost.build/5643/
+# Since it is common practice to write
+# exe hello : hello.cpp hello.rc
+# we change the name of object created from RC file, to avoid conflict with
+# hello.cpp. The reason we generate OBJ and not RES, is that gcc does not seem
+# to like RES files, but works OK with OBJ (see
+# http://article.gmane.org/gmane.comp.lib.boost.build/5643).
 #
 # Using 'register-c-compiler' adds the build directory to INCLUDES
 generators.register-c-compiler rc.compile.resource : RC : OBJ(%_res) ;
 
 # Register scanner for resources
-class res-scanner : scanner
+class res-scanner : scanner
 {
- import regex virtual-target path scanner ;
-
+ import path ;
+ import regex ;
+ import scanner ;
+ import virtual-target ;
+
     rule __init__ ( includes * )
     {
         scanner.__init__ ;
-
         self.includes = $(includes) ;
- }
+ }
 
     rule pattern ( )
     {
@@ -112,44 +112,43 @@
         local quoted = [ regex.transform $(matches) : "#include[ ]*\"([^\"]+)\"" ] ;
         local res = [ regex.transform $(matches) : "[^ ]+[ ]+(BITMAP|CURSOR|FONT|ICON|MESSAGETABLE|RT_MANIFEST)[ ]+(([^ \"]+)|\"([^\"]+)\")" : 3 4 ] ;
 
- # Icons and other includes may referenced as
+ # Icons and other includes may be referenced as
         #
         # IDR_MAINFRAME ICON "res\\icon.ico"
         #
- # so we have to replace double backslashes to single ones.
+ # so we have to replace double backslashes with single ones.
         res = [ regex.replace-list $(res) : "\\\\\\\\" : "/" ] ;
 
- # CONSIDER: the new scoping rule seem to defeat "on target" variables.
- local g = [ on $(target) return $(HDRGRIST) ] ;
+ # CONSIDER: the new scoping rules seem to defeat "on target" variables.
+ local g = [ on $(target) return $(HDRGRIST) ] ;
         local b = [ NORMALIZE_PATH $(binding:D) ] ;
 
- # Attach binding of including file to included targets.
- # When target is directly created from virtual target
- # this extra information is unnecessary. But in other
- # cases, it allows to distinguish between two headers of the
- # same name included from different places.
- # We don't need this extra information for angle includes,
- # since they should not depend on including file (we can't
- # get literal "." in include path).
+ # Attach binding of including file to included targets. When a target is
+ # directly created from a virtual target this extra information is
+ # unnecessary. But in other cases, it allows us to distinguish between
+ # two headers of the same name included from different places. We do not
+ # need this extra information for angle includes, since they should not
+ # depend on the including file (we can not get literal "." in the
+ # include path).
         local g2 = $(g)"#"$(b) ;
-
+
         angle = $(angle:G=$(g)) ;
         quoted = $(quoted:G=$(g2)) ;
         res = $(res:G=$(g2)) ;
-
- local all = $(angle) $(quoted) ;
+
+ local all = $(angle) $(quoted) $(res) ;
 
         INCLUDES $(target) : $(all) ;
- DEPENDS $(target) : $(res) ;
- NOCARE $(all) $(res) ;
+ NOCARE $(all) ;
         SEARCH on $(angle) = $(self.includes:G=) ;
- SEARCH on $(quoted) = $(b) $(self.includes:G=) ;
- SEARCH on $(res) = $(b) $(self.includes:G=) ;
-
- # Just propagate current scanner to includes, in a hope
- # that includes do not change scanners.
+ SEARCH on $(quoted) $(res) = $(b) $(self.includes:G=) ;
+
+ # Just propagate the current scanner to includes, in hope that includes
+ # do not change scanners.
         scanner.propagate $(__name__) : $(angle) $(quoted) : $(target) ;
- }
+
+ ISFILE $(all) ;
+ }
 }
 
 scanner.register res-scanner : include ;

Modified: branches/release/tools/build/v2/tools/stage.jam
==============================================================================
--- branches/release/tools/build/v2/tools/stage.jam (original)
+++ branches/release/tools/build/v2/tools/stage.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,21 +2,21 @@
 # Copyright 2005, 2006 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # This module defines the 'install' rule, used to copy a set of targets to a
 # single location.
 
-import targets ;
 import "class" : new ;
-import errors ;
-import type ;
-import generators ;
 import feature ;
-import project ;
-import virtual-target ;
+import generators ;
 import path ;
+import project ;
+import targets ;
+import type ;
 import types/register ;
+import virtual-target ;
 
 
 feature.feature <install-dependencies> : off on : incidental ;
@@ -31,19 +31,23 @@
 
 class install-target-class : basic-target
 {
+ import "class" : new ;
     import feature ;
- import project ;
- import type ;
- import errors ;
     import generators ;
     import path ;
- import stage ;
- import "class" : new ;
+ import project ;
     import property ;
     import property-set ;
+ import stage ;
+ import type ;
 
- rule __init__ ( name-and-dir : project : sources * : requirements * : default-build * )
+ rule __init__ ( name-and-dir : project : sources * : requirements * :
+ default-build * : usage-requirements * )
     {
+ # The usage-requirements specified here are ignored but are taken as a
+ # parameter to have this metatarget class have the same standard
+ # instantiation interface as all the other Boost Build metatarget
+ # classes.
         basic-target.__init__ $(name-and-dir) : $(project) : $(sources) :
             $(requirements) : $(default-build) ;
     }
@@ -140,8 +144,9 @@
 
         if $(ename) && $(source-targets[2])
         {
- errors.error "When <name> property is used in 'install', only one"
- "source is allowed" ;
+ import errors : error : $(__name__) : errors.error ;
+ errors.error When <name> property is used "in" 'install', only one
+ source is allowed. ;
         }
 
         local result ;
@@ -159,7 +164,9 @@
             {
                 if $(ename)
                 {
- errors.error "In 'install': <name> property specified with target that requires relinking." ;
+ import errors : error : $(__name__) : errors.error ;
+ errors.error In 'install': <name> property specified with
+ target that requires relinking. ;
                 }
                 else
                 {
@@ -176,7 +183,9 @@
 
             if ! $(staged-targets)
             {
- errors.error "Unable to generate staged version of " [ $(source).str ] ;
+ import errors : error : $(__name__) : errors.error ;
+ errors.error Unable to generate staged version of
+ [ $(source).str ] ;
             }
 
             for t in $(staged-targets)
@@ -226,8 +235,8 @@
             }
             else if ! $(included-types)
             {
- # Don't install typeless target if there is an explicit list of
- # allowed types.
+ # Do not install typeless targets if there is an explicit list
+ # of allowed types.
                 result += $(r) ;
             }
         }
@@ -246,10 +255,10 @@
             s += [ $(t).creating-subvariant ] ;
         }
         s = [ sequence.unique $(s) ] ;
-
+
         local result = [ new set ] ;
         $(result).add $(targets) ;
-
+
         for local i in $(s)
         {
             $(i).all-referenced-targets $(result) ;
@@ -324,8 +333,9 @@
 rule symlink ( name : project : source : properties )
 {
     local a = [ new action $(source) : symlink.ln : $(properties) ] ;
- return [ new file-target $(name) exact : [ $(source).type ] : $(project) :
- $(a) ] ;
+ local t = [ new file-target $(name) exact : [ $(source).type ] : $(project)
+ : $(a) ] ;
+ return [ virtual-target.register $(t) ] ;
 }
 
 
@@ -357,38 +367,25 @@
 
     rule run ( project name ? : property-set : source : multiple ? )
     {
- local need-relink ;
-
- if [ $(property-set).get <os> ] in NT CYGWIN ||
- [ $(property-set).get <target-os> ] in windows cygwin
- {
- }
- else
+ local stage-rule = stage.copy-file ;
+
+ if ! [ $(property-set).get <os> ] in NT CYGWIN &&
+ ! [ $(property-set).get <target-os> ] in windows cygwin
         {
- # See if the dll-path properties are not changed during
- # install. If so, copy, don't relink.
+ # If dll-path properties have been changed for the stage target,
+ # relink instead of copying.
             local a = [ $(source).action ] ;
             local p = [ $(a).properties ] ;
             local original = [ $(p).get <dll-path> ] ;
             local current = [ $(property-set).get <dll-path> ] ;
-
+
             if $(current) != $(original)
             {
- need-relink = true ;
- }
- }
-
-
- if $(need-relink)
- {
- return [ stage.relink-file $(project)
- : $(source) : $(property-set) ] ;
- }
- else
- {
- return [ stage.copy-file $(project)
- : $(source) : $(property-set) ] ;
+ stage-rule = stage.relink-file ;
+ }
         }
+
+ return [ $(stage-rule) $(project) : $(source) : $(property-set) ] ;
     }
 }
 
@@ -410,8 +407,8 @@
 
     rule __init__ ( )
     {
- generator.__init__ install-shared-lib : SHARED_LIB
- : INSTALLED_SHARED_LIB ;
+ generator.__init__ install-shared-lib : SHARED_LIB :
+ INSTALLED_SHARED_LIB ;
     }
 
     rule run ( project name ? : property-set : source : multiple ? )
@@ -458,8 +455,9 @@
             # If the name is in the form NNN.XXX.YYY.ZZZ, where all 'X', 'Y' and
             # 'Z' are numbers, we need to create NNN.XXX and NNN.XXX.YYY
             # symbolic links.
- local m = [ MATCH (.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$
- : [ $(copied).name ] ] ;
+ local m = [ MATCH
+ (.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$ :
+ [ $(copied).name ] ] ;
             if $(m)
             {
                 # Symlink without version at all is used to make
@@ -472,15 +470,15 @@
                 # libfoo.N. That happens when the library makes some binary
                 # compatibility guarantees. If not, it is possible to skip those
                 # symlinks.
- local suppress =
- [ $(property-set).get <install-no-version-symlinks> ] ;
+ local suppress = [ $(property-set).get
+ <install-no-version-symlinks> ] ;
 
                 if $(suppress) != "on"
                 {
- result += [ stage.symlink $(m[1]).$(m[2]) : $(project)
- : $(copied) : $(property-set) ] ;
- result += [ stage.symlink $(m[1]).$(m[2]).$(m[3]) : $(project)
- : $(copied) : $(property-set) ] ;
+ result += [ stage.symlink $(m[1]).$(m[2]) : $(project) :
+ $(copied) : $(property-set) ] ;
+ result += [ stage.symlink $(m[1]).$(m[2]).$(m[3]) :
+ $(project) : $(copied) : $(property-set) ] ;
                 }
             }
 
@@ -507,16 +505,13 @@
 
     if <tag> in $(requirements:G)
     {
- errors.user-error
- "The <tag> property is not allowed for the 'install' rule" ;
+ import errors ;
+ errors.user-error The <tag> property is not allowed for the 'install'
+ rule. ;
     }
 
- targets.main-target-alternative
- [ new install-target-class $(name) : $(project)
- : [ targets.main-target-sources $(sources) : $(name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
- ] ;
+ targets.create-metatarget install-target-class : $(project) : $(name) :
+ $(sources) : $(requirements) : $(default-build) ;
 }
 
 

Modified: branches/release/tools/build/v2/tools/stlport.jam
==============================================================================
--- branches/release/tools/build/v2/tools/stlport.jam (original)
+++ branches/release/tools/build/v2/tools/stlport.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,8 +1,8 @@
 # Copyright Gennadiy Rozental
-# Copyright 2006 Rene Rivera
-# Copyright 2003, 2004, 2006 Vladimir Prus
-# 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)
+# Copyright 2006 Rene Rivera
+# Copyright 2003, 2004, 2006 Vladimir Prus
+# 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)
 
 # The STLPort is usable by means of 'stdlib' feature. When
 # stdlib=stlport is specified, default version of STLPort will be used,
@@ -86,7 +86,7 @@
         self.libraries = $(libraries) ;
         self.version = $(version) ;
         self.version.5 = [ MATCH "^(5[.][0123456789]+).*" : $(version) ] ;
-
+
         local requirements ;
         requirements += <stdlib-stlport:version>$(self.version) ;
         self.requirements = [ property-set.create $(requirements) ] ;
@@ -120,10 +120,10 @@
         if $(self.version.5)
         {
             # Version 5.x
-
- # STLport host IO streams no longer supported. So we always
+
+ # STLport host IO streams no longer supported. So we always
             # need libraries.
-
+
             # name: stlport(stl)?[dg]?(_static)?.M.R
             local name = stlport ;
             if [ feature.get-values <runtime-debugging> : $(raw) ] = "on"
@@ -142,31 +142,35 @@
                 name += _static ;
             }
 
- # Starting with version 5.2.0, the STLport static libraries no longer
- # include a version number in their name
+ # Starting with version 5.2.0, the STLport static libraries no
+ # longer include a version number in their name
             local version.pre.5.2 = [ MATCH "^(5[.][01]+).*" : $(version) ] ;
- if $(version.pre.5.2) || [ feature.get-values <runtime-link> : $(raw) ] != "static"
+ if $(version.pre.5.2) || [ feature.get-values <runtime-link> :
+ $(raw) ] != "static"
             {
                 name += .$(self.version.5) ;
             }
-
+
             name = $(name:J=) ;
-
+
             if [ feature.get-values <install-dependencies> : $(raw) ] = "on"
             {
                 #~ Allow explicitly asking to install the STLport lib by
- #~ refering to it directly: /stlport//stlport/<install-dependencies>on
- #~ This allows for install packaging of all libs one might need for
- #~ a standalone distribution.
+ #~ referring to it directly:
+ #~ /stlport//stlport/<install-dependencies>on
+ #~ This allows for install packaging of all libs one might need
+ #~ for a standalone distribution.
                 import path : make : path-make ;
                 local runtime-link
                     = [ feature.get-values <runtime-link> : $(raw) ] ;
                 local lib-file.props
                     = [ property-set.create $(raw) <link>$(runtime-link) ] ;
                 local lib-file.prefix
- = [ type.generated-target-prefix $(runtime-link:U)_LIB : $(lib-file.props) ] ;
+ = [ type.generated-target-prefix $(runtime-link:U)_LIB :
+ $(lib-file.props) ] ;
                 local lib-file.suffix
- = [ type.generated-target-suffix $(runtime-link:U)_LIB : $(lib-file.props) ] ;
+ = [ type.generated-target-suffix $(runtime-link:U)_LIB :
+ $(lib-file.props) ] ;
                 lib-file.prefix
                     ?= "" "lib" ;
                 lib-file.suffix
@@ -175,18 +179,20 @@
                     = [ GLOB $(self.libraries) [ modules.peek : PATH ] :
                         $(lib-file.prefix)$(name).$(lib-file.suffix) ] ;
                 lib-file
- = [ new file-reference [ path-make $(lib-file[1]) ] : $(self.project) ] ;
+ = [ new file-reference [ path-make $(lib-file[1]) ] :
+ $(self.project) ] ;
                 lib-file
                     = [ $(lib-file).generate "" ] ;
                 local lib-file.requirements
                     = [ targets.main-target-requirements
                         [ $(lib-file.props).raw ] <file>$(lib-file[-1])
                         : $(self.project) ] ;
- return [ generators.construct $(self.project) $(name) : LIB : $(lib-file.requirements) ] ;
+ return [ generators.construct $(self.project) $(name) : LIB :
+ $(lib-file.requirements) ] ;
             }
             else
             {
- #~ Otherwise, it's just a regular usage of the library.
+ #~ Otherwise, it is just regular library usage.
                 return [ generators.construct
                     $(self.project) $(name) : SEARCHED_LIB : $(property-set) ] ;
             }
@@ -195,7 +201,7 @@
         {
             # We don't need libraries if host istreams are used. For
             # msvc, automatic library selection will be used.
-
+
             # name: stlport_<toolset>(_stldebug)?
             local name = stlport ;
             name = $(name)_$(toolset) ;
@@ -259,7 +265,7 @@
                     <define>_STLP_THREADS=1 ;
             }
         }
-
+
         return [ property-set.create $(usage-requirements) ] ;
     }
 }

Modified: branches/release/tools/build/v2/tools/testing-aux.jam
==============================================================================
--- branches/release/tools/build/v2/tools/testing-aux.jam (original)
+++ branches/release/tools/build/v2/tools/testing-aux.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -175,28 +175,38 @@
 actions unit-test
 {
     $(PATH_SETUP)
- $(LAUNCHER) $(>) $(ARGS) && $(.MAKE_FILE) $(<)
+ $(LAUNCHER) "$(>)" $(ARGS) && $(.MAKE_FILE) "$(<)"
 }
 
+# Note that this rule may be called multiple times for a single target in case
+# there are multiple actions operating on the same target in sequence. One such
+# example are msvc exe targets first created by a linker action and then updated
+# with an embedded manifest file by a separate action.
 rule record-time ( target : source : start end user system )
 {
     local src-string = [$(source:G=:J=",")"] " ;
     USER_TIME on $(target) += $(src-string)$(user) ;
     SYSTEM_TIME on $(target) += $(src-string)$(system) ;
+
+ # We need the following variables because attempting to perform such
+ # variable expansion in actions would not work due to quotes getting treated
+ # as regular characters.
+ USER_TIME_SECONDS on $(target) += $(src-string)$(user)" seconds" ;
+ SYSTEM_TIME_SECONDS on $(target) += $(src-string)$(system)" seconds" ;
 }
 
-# Calling this rule requests that Boost Build time how long it taks to build the
-# 'source' target and display the results both on the standard output and in the
-# 'target' file.
+# Calling this rule requests that Boost Build time how long it takes to build
+# the 'source' target and display the results both on the standard output and in
+# the 'target' file.
 #
-rule time ( target : source : properties * )
+rule time ( target : sources + : properties * )
 {
     # Set up rule for recording timing information.
- __TIMING_RULE__ on $(source) = testing.record-time $(target) ;
+ __TIMING_RULE__ on $(sources) = testing.record-time $(target) ;
 
- # Make sure that the source is rebuilt any time we need to retrieve that
+ # Make sure the sources get rebuilt any time we need to retrieve that
     # information.
- REBUILDS $(target) : $(source) ;
+ REBUILDS $(target) : $(sources) ;
 }
 
 
@@ -205,6 +215,6 @@
     echo user: $(USER_TIME)
     echo system: $(SYSTEM_TIME)
 
- echo user: $(USER_TIME)" seconds" > "$(<)"
- echo system: $(SYSTEM_TIME)" seconds" >> "$(<)"
+ echo user: $(USER_TIME_SECONDS) > "$(<)"
+ echo system: $(SYSTEM_TIME_SECONDS) >> "$(<)"
 }

Modified: branches/release/tools/build/v2/tools/testing.jam
==============================================================================
--- branches/release/tools/build/v2/tools/testing.jam (original)
+++ branches/release/tools/build/v2/tools/testing.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -533,7 +533,7 @@
 actions unit-test
 {
     $(PATH_SETUP)
- $(LAUNCHER) $(>) $(ARGS) && $(.MAKE_FILE) $(<)
+ $(LAUNCHER) "$(>)" $(ARGS) && $(.MAKE_FILE) "$(<)"
 }
 
 
@@ -541,33 +541,46 @@
     : : compile compile-fail run run-fail link link-fail ;
 
 
+# This is a composing generator to support cases where a generator for the
+# specified target constructs other targets as well. One such example is msvc's
+# exe generator that constructs both EXE and PDB targets.
 type.register TIME : time ;
-generators.register-standard testing.time : : TIME ;
+generators.register-composing testing.time : : TIME ;
 
 
+# Note that this rule may be called multiple times for a single target in case
+# there are multiple actions operating on the same target in sequence. One such
+# example are msvc exe targets first created by a linker action and then updated
+# with an embedded manifest file by a separate action.
 rule record-time ( target : source : start end user system )
 {
     local src-string = [$(source:G=:J=",")"] " ;
     USER_TIME on $(target) += $(src-string)$(user) ;
     SYSTEM_TIME on $(target) += $(src-string)$(system) ;
+
+ # We need the following variables because attempting to perform such
+ # variable expansion in actions would not work due to quotes getting treated
+ # as regular characters.
+ USER_TIME_SECONDS on $(target) += $(src-string)$(user)" seconds" ;
+ SYSTEM_TIME_SECONDS on $(target) += $(src-string)$(system)" seconds" ;
 }
 
 
 IMPORT testing : record-time : : testing.record-time ;
 
 
-# Calling this rule requests that Boost Build time how long it taks to build the
-# 'source' target and display the results both on the standard output and in the
-# 'target' file.
+# Calling this rule requests that Boost Build time how long it takes to build
+# the 'source' target and display the results both on the standard output and in
+# the 'target' file.
 #
-rule time ( target : source : properties * )
+rule time ( target : sources + : properties * )
 {
     # Set up rule for recording timing information.
- __TIMING_RULE__ on $(source) = testing.record-time $(target) ;
+ __TIMING_RULE__ on $(sources) = testing.record-time $(target) ;
 
- # Make sure that the source is rebuilt any time we need to retrieve that
+ # Make sure the sources get rebuilt any time we need to retrieve that
     # information.
- REBUILDS $(target) : $(source) ;
+ REBUILDS $(target) : $(sources) ;
 }
 
 
@@ -576,6 +589,6 @@
     echo user: $(USER_TIME)
     echo system: $(SYSTEM_TIME)
 
- echo user: $(USER_TIME)" seconds" > "$(<)"
- echo system: $(SYSTEM_TIME)" seconds" >> "$(<)"
+ echo user: $(USER_TIME_SECONDS) > "$(<)"
+ echo system: $(SYSTEM_TIME_SECONDS) >> "$(<)"
 }

Modified: branches/release/tools/build/v2/tools/testing.py
==============================================================================
--- branches/release/tools/build/v2/tools/testing.py (original)
+++ branches/release/tools/build/v2/tools/testing.py 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -286,8 +286,11 @@
 toolset.flags("testing.unit-test", "LAUNCHER", [], ["<testing.launcher>"])
 toolset.flags("testing.unit-test", "ARGS", [], ["<testing.arg>"])
 
+# This is a composing generator to support cases where a generator for the
+# specified target constructs other targets as well. One such example is msvc's
+# exe generator that constructs both EXE and PDB targets.
 type.register("TIME", ["time"])
-generators.register_standard("testing.time", [], ["TIME"])
+generators.register_composing("testing.time", [], ["TIME"])
 
 
 # The following code sets up actions for this module. It's pretty convoluted,

Modified: branches/release/tools/build/v2/tools/types/cpp.jam
==============================================================================
--- branches/release/tools/build/v2/tools/types/cpp.jam (original)
+++ branches/release/tools/build/v2/tools/types/cpp.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,10 +1,13 @@
-# Copyright David Abrahams 2004.
+# Copyright 2004 David Abrahams
 # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
 # Copyright 2010 Rene Rivera
 # Distributed under the Boost Software License, Version 1.0.
-# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-import type ;
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
 import scanner ;
+import type ;
+
 
 class c-scanner : scanner
 {
@@ -20,8 +23,8 @@
 
         for local i in $(includes)
         {
- self.includes += [ sequence.transform path.native
- : [ regex.split $(i:G=) "&&" ] ] ;
+ self.includes += [ sequence.transform path.native : [ regex.split
+ $(i:G=) "&&" ] ] ;
         }
     }
 
@@ -32,21 +35,22 @@
 
     rule process ( target : matches * : binding )
     {
- local angle = [ regex.transform $(matches) : "<(.*)>" ] ;
+ local angle = [ regex.transform $(matches) : "<(.*)>" ] ;
         angle = [ sequence.transform path.native : $(angle) ] ;
         local quoted = [ regex.transform $(matches) : "\"(.*)\"" ] ;
         quoted = [ sequence.transform path.native : $(quoted) ] ;
 
- # CONSIDER: the new scoping rule seem to defeat "on target" variables.
+ # CONSIDER: the new scoping rules seem to defeat "on target" variables.
         local g = [ on $(target) return $(HDRGRIST) ] ;
         local b = [ NORMALIZE_PATH $(binding:D) ] ;
 
         # Attach binding of including file to included targets. When a target is
- # directly created from virtual target this extra information is
+ # directly created from a virtual target this extra information is
         # unnecessary. But in other cases, it allows us to distinguish between
         # two headers of the same name included from different places. We do not
         # need this extra information for angle includes, since they should not
- # depend on including file (we can not get literal "." in include path).
+ # depend on the including file (we can not get literal "." in the
+ # include path).
         local g2 = $(g)"#"$(b) ;
 
         angle = $(angle:G=$(g)) ;
@@ -59,11 +63,11 @@
         SEARCH on $(angle) = $(self.includes:G=) ;
         SEARCH on $(quoted) = $(b) $(self.includes:G=) ;
 
- # Just propagate the current scanner to includes in hope that includes
+ # Just propagate the current scanner to includes, in hope that includes
         # do not change scanners.
- scanner.propagate $(__name__) : $(angle) $(quoted) : $(target) ;
+ scanner.propagate $(__name__) : $(all) : $(target) ;
 
- ISFILE $(angle) $(quoted) ;
+ ISFILE $(all) ;
     }
 }
 

Modified: branches/release/tools/build/v2/tools/xsltproc-config.jam
==============================================================================
--- branches/release/tools/build/v2/tools/xsltproc-config.jam (original)
+++ branches/release/tools/build/v2/tools/xsltproc-config.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,36 +2,35 @@
 #~ 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)
 
-# Automatic configuration for Python tools and librries. To use, just import this module.
+# Automatic configuration for the xsltproc toolset. To use, just import this
+# module.
 
 import os ;
 import toolset : using ;
 
-if [ os.name ] = NT
+
+local rule locate-executable ( name )
 {
- local xsltproc-path = [ GLOB [ modules.peek : PATH ] "C:\\Boost\\bin" : xsltproc\.exe ] ;
- xsltproc-path = $(xsltproc-path[1]) ;
-
- if $(xsltproc-path)
+ local path = [ modules.peek : PATH ] ;
+ local exe ;
+ if [ os.name ] = NT
+ {
+ exe = [ GLOB $(path) "C:\\Boost\\bin" : $(name)\.exe ] ;
+ }
+ else
     {
- if --debug-configuration in [ modules.peek : ARGV ]
- {
- ECHO "notice:" using xsltproc ":" $(xsltproc-path) ;
- }
- using xsltproc : $(xsltproc-path) ;
+ exe = [ GLOB $(path) : $(name) ] ;
     }
+ return $(exe[1]) ;
 }
-else
+
+
+local xsltproc-exe = [ locate-executable xsltproc ] ;
+if $(xsltproc-exe)
 {
- local xsltproc-path = [ GLOB [ modules.peek : PATH ] : xsltproc ] ;
- xsltproc-path = $(xsltproc-path[1]) ;
-
- if $(xsltproc-path)
+ if --debug-configuration in [ modules.peek : ARGV ]
     {
- if --debug-configuration in [ modules.peek : ARGV ]
- {
- ECHO "notice:" using xsltproc ":" $(xsltproc-path) ;
- }
- using xsltproc : $(xsltproc-path) ;
+ ECHO notice: using xsltproc ":" $(xsltproc-exe) ;
     }
+ using xsltproc : $(xsltproc-exe) ;
 }

Modified: branches/release/tools/build/v2/tools/xsltproc.jam
==============================================================================
--- branches/release/tools/build/v2/tools/xsltproc.jam (original)
+++ branches/release/tools/build/v2/tools/xsltproc.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,18 +5,15 @@
 
 # This module defines rules to apply an XSLT stylesheet to an XML file using the
 # xsltproc driver, part of libxslt.
-#
-# Note: except for 'init', this modules does not provide any rules for end
-# users.
 
-import feature ;
-import regex ;
-import sequence ;
 import common ;
-import os ;
+import feature ;
 import modules ;
+import os ;
 import path ;
-import errors ;
+import regex ;
+import sequence ;
+
 
 feature.feature xsl:param : : free ;
 feature.feature xsl:path : : free ;
@@ -36,6 +33,7 @@
     }
 }
 
+
 rule freeze-config ( )
 {
     if ! $(.config-frozen)
@@ -48,40 +46,49 @@
     }
 }
 
-rule modify-config
+
+rule modify-config ( )
 {
     if $(.config-frozen)
     {
- errors.user-error "xsltproc: Cannot change xsltproc command after it has been used." ;
+ import errors ;
+ errors.user-error
+ "xsltproc: Cannot change xsltproc command after it has been used." ;
     }
 }
 
+
 rule check-xsltproc ( )
 {
     if $(.xsltproc)
     {
- local status = [ SHELL "\"$(.xsltproc)\" -V" : no-output : exit-status ] ;
- if $(status[2]) != "0"
+ local status = [ SHELL "\"$(.xsltproc)\" -V" : no-output : exit-status ]
+ ;
+ if $(status[2]) != 0
         {
+ import errors ;
             errors.user-error "xsltproc: Could not run \"$(.xsltproc)\" -V." ;
         }
     }
 }
 
+
 # Returns a non-empty string if a cygwin xsltproc binary was specified.
+#
 rule is-cygwin ( )
 {
     freeze-config ;
     return $(.is-cygwin) ;
 }
 
+
 rule .is-cygwin ( xsltproc )
 {
     if [ os.on-windows ]
     {
         local file = [ path.make [ modules.binding $(__name__) ] ] ;
- local dir = [ path.native
- [ path.join [ path.parent $(file) ] xsltproc ] ] ;
+ local dir = [ path.native [ path.join [ path.parent $(file) ] xsltproc ]
+ ] ;
         if [ os.name ] = CYGWIN
         {
             dir = $(dir:W) ;
@@ -96,12 +103,11 @@
     }
 }
 
+
 rule compute-xslt-flags ( target : properties * )
 {
- local flags ;
-
     # Raw flags.
- flags += [ feature.get-values <flags> : $(properties) ] ;
+ local flags = [ feature.get-values <flags> : $(properties) ] ;
 
     # Translate <xsl:param> into command line flags.
     for local param in [ feature.get-values <xsl:param> : $(properties) ]
@@ -118,7 +124,8 @@
 
     # Take care of implicit dependencies.
     local other-deps ;
- for local dep in [ feature.get-values <implicit-dependency> : $(properties) ]
+ for local dep in [ feature.get-values <implicit-dependency> : $(properties)
+ ]
     {
         other-deps += [ $(dep:G=).creating-subvariant ] ;
     }
@@ -138,7 +145,8 @@
 }
 
 
-local rule .xsltproc ( target : source stylesheet : properties * : dirname ? : action )
+local rule .xsltproc ( target : source stylesheet : properties * : dirname ? :
+ action )
 {
     freeze-config ;
     STYLESHEET on $(target) = $(stylesheet) ;
@@ -147,7 +155,8 @@
 
     for local catalog in [ feature.get-values <catalog> : $(properties) ]
     {
- CATALOG = [ common.variable-setting-command XML_CATALOG_FILES : $(catalog:T) ] ;
+ CATALOG = [ common.variable-setting-command XML_CATALOG_FILES :
+ $(catalog:T) ] ;
     }
 
     if [ os.on-windows ] && ! [ is-cygwin ]
@@ -161,13 +170,15 @@
 
 rule xslt ( target : source stylesheet : properties * )
 {
- return [ .xsltproc $(target) : $(source) $(stylesheet) : $(properties) : : xslt-xsltproc ] ;
+ return [ .xsltproc $(target) : $(source) $(stylesheet) : $(properties) : :
+ xslt-xsltproc ] ;
 }
 
 
 rule xslt-dir ( target : source stylesheet : properties * : dirname )
 {
- return [ .xsltproc $(target) : $(source) $(stylesheet) : $(properties) : $(dirname) : xslt-xsltproc-dir ] ;
+ return [ .xsltproc $(target) : $(source) $(stylesheet) : $(properties) :
+ $(dirname) : xslt-xsltproc-dir ] ;
 }
 
 actions xslt-xsltproc.windows

Modified: branches/release/tools/build/v2/tools/zlib.jam
==============================================================================
--- branches/release/tools/build/v2/tools/zlib.jam (original)
+++ branches/release/tools/build/v2/tools/zlib.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,4 +1,5 @@
 # Copyright (c) 2010 Vladimir Prus.
+# Copyright (c) 2013 Steven Watanabe
 #
 # Use, modification and distribution is subject to the Boost Software
 # License Version 1.0. (See accompanying file LICENSE_1_0.txt or
@@ -10,83 +11,217 @@
 #
 # /zlib//zlib -- The zlib library
 
-
-# In addition to direct purpose of supporting zlib, this module also
-# serves as canonical example of how third-party condiguration works
-# in Boost.Build. The operation is as follows
-#
-# - For each 'using zlib : condition ... : ...' we create a target alternative
-# for zlib, with the specified condition.
-# - There's one target alternative for 'zlib' with no specific condition
-# properties.
-#
-# Two invocations of 'using zlib' with the same condition but different
-# properties are not permitted, e.g.:
-#
-# using zlib : condition <target-os>windows : include foo ;
-# using zlib : condition <target-os>windows : include bar ;
-#
-# is in error. One exception is for empty condition, 'using' without any
-# parameters is overridable. That is:
-#
-# using zlib ;
-# using zlib : include foo ;
-#
-# Is OK then the first 'using' is ignored. Likewise if the order of the statements
-# is reversed.
-#
-# When 'zlib' target is built, a target alternative is selected as usual for
-# Boost.Build. The selected alternative is a custom target class, which:
-#
-# - calls ac.find-include-path to find header path. If explicit path is provided
-# in 'using', only that path is checked, and if no header is found there, error
-# is emitted. Otherwise, we check a directory specified using ZLIB_INCLUDE
-# environment variable, and failing that, in standard directories.
-# [TODO: document sysroot handling]
-# - calls ac.find-library to find the library, in an identical fashion.
-#
-
 import project ;
 import ac ;
 import errors ;
 import "class" : new ;
 import targets ;
-
-project.initialize $(__name__) ;
-project = [ project.current ] ;
-project zlib ;
+import path ;
+import modules ;
+import errors ;
+import indirect ;
+import property ;
+import property-set ;
 
 header = zlib.h ;
 names = z zlib zll zdll ;
 
-.default-alternative = [ new ac-library zlib : $(project) ] ;
-$(.default-alternative).set-header $(header) ;
-$(.default-alternative).set-default-names $(names) ;
-targets.main-target-alternative $(.default-alternative) ;
+sources = adler32.c compress.c
+ crc32.c deflate.c gzclose.c gzio.c gzlib.c gzread.c gzwrite.c
+ infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c ;
+
+library-id = 0 ;
 
-rule init ( * : * )
+if --debug-configuration in [ modules.peek : ARGV ]
 {
- if ! $(condition)
- {
- # Special case the no-condition case so that 'using' without parameters
- # can mix with more specific 'using'.
- $(.default-alternative).reconfigure $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
- }
- else
- {
- # FIXME: consider if we should allow overriding definitions for a given
- # condition -- e.g. project-config.jam might want to override whatever is
- # in user-config.jam.
- local mt = [ new ac-library zlib : $(project)
- : $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
- $(mt).set-header $(header) ;
- $(mt).set-default-names $(names) ;
- targets.main-target-alternative $(mt) ;
- }
+ .debug = true ;
 }
 
+# Initializes the zlib library.
+#
+# zlib can be configured either to use pre-existing binaries
+# or to build the library from source.
+#
+# Options for configuring a prebuilt zlib::
+#
+# <search>
+# The directory containing the zlib binaries.
+# <name>
+# Overrides the default library name.
+# <include>
+# The directory containing the zlib headers.
+#
+# If none of these options is specified, then the environmental
+# variables ZLIB_LIBRARY_PATH, ZLIB_NAME, and ZLIB_INCLUDE will
+# be used instead.
+#
+# Options for building zlib from source::
+#
+# <source>
+# The zlib source directory. Defaults to the environmental variable
+# ZLIB_SOURCE.
+# <tag>
+# A rule which computes the actual name of the compiled
+# libraries based on the build properties. Ignored
+# when using precompiled binaries.
+# <build-name>
+# The base name to use for the compiled library. Ignored
+# when using precompiled binaries.
+#
+# Examples::
+#
+# # Find zlib in the default system location
+# using zlib ;
+# # Build zlib from source
+# using zlib : 1.2.7 : <source>/home/steven/zlib-1.2.7 ;
+# # Find zlib in /usr/local
+# using zlib : 1.2.7
+# : <include>/usr/local/include <search>/usr/local/lib ;
+# # Build zlib from source for msvc and find
+# # prebuilt binaries for gcc.
+# using zlib : 1.2.7 : <source>C:/Devel/src/zlib-1.2.7 : <toolset>msvc ;
+# using zlib : 1.2.7 : : <toolset>gcc ;
+#
+rule init (
+ version ?
+ # The zlib version (currently ignored)
+
+ : options *
+ # A list of the options to use
+
+ : requirements *
+ # The requirements for the zlib target
+
+ : is-default ?
+ # Default configurations are only used when zlib
+ # has not yet been configured.
+ )
+{
+ local caller = [ project.current ] ;
+
+ if ! $(.initialized)
+ {
+ .initialized = true ;
 
+ project.initialize $(__name__) ;
+ .project = [ project.current ] ;
+ project zlib ;
+ }
 
+ local library-path = [ property.select <search> : $(options) ] ;
+ library-path = $(library-path:G=) ;
+ local include-path = [ property.select <include> : $(options) ] ;
+ include-path = $(include-path:G=) ;
+ local source-path = [ property.select <source> : $(options) ] ;
+ source-path = $(source-path:G=) ;
+ local library-name = [ property.select <name> : $(options) ] ;
+ library-name = $(library-name:G=) ;
+ local tag = [ property.select <tag> : $(options) ] ;
+ tag = $(tag:G=) ;
+ local build-name = [ property.select <build-name> : $(options) ] ;
+ build-name = $(build-name:G=) ;
+
+ condition = [ property-set.create $(requirements) ] ;
+ condition = [ property-set.create [ $(condition).base ] ] ;
+
+ local no-build-from-source ;
+ # Ignore environmental ZLIB_SOURCE if this initialization
+ # requested to search for a specific pre-built library.
+ if $(library-path) || $(include-path) || $(library-name)
+ {
+ if $(source-path) || $(tag) || $(build-name)
+ {
+ errors.user-error "incompatible options for zlib:"
+ [ property.select <search> <include> <name> : $(options) ] "and"
+ [ property.select <source> <tag> <build-name> : $(options) ] ;
+ }
+ else
+ {
+ no-build-from-source = true ;
+ }
+ }
 
+ source-path ?= [ modules.peek : ZLIB_SOURCE ] ;
+
+ if $(.configured.$(condition))
+ {
+ if $(is-default)
+ {
+ if $(.debug)
+ {
+ ECHO "notice: [zlib] zlib is already configured" ;
+ }
+ }
+ else
+ {
+ errors.user-error "zlib is already configured" ;
+ }
+ return ;
+ }
+ else if $(source-path) && ! $(no-build-from-source)
+ {
+ build-name ?= z ;
+ library-id = [ CALC $(library-id) + 1 ] ;
+ tag = [ MATCH ^@?(.*)$ : $(tag) ] ;
+ if $(tag) && ! [ MATCH ^([^%]*)%([^%]+)$ : $(tag) ]
+ {
+ tag = [ indirect.make $(tag) : [ $(caller).project-module ] ] ;
+ }
+ sources = [ path.glob $(source-path) : $(sources) ] ;
+ if $(.debug)
+ {
+ ECHO "notice: [zlib] Building zlib from source as $(build-name)" ;
+ if $(condition)
+ {
+ ECHO "notice: [zlib] Condition" [ $(condition).raw ] ;
+ }
+ if $(sources)
+ {
+ ECHO "notice: [zlib] found zlib source in $(source-path)" ;
+ }
+ else
+ {
+ ECHO "warning: [zlib] could not find zlib source in $(source-path)" ;
+ }
+ }
+ local target ;
+ if $(sources) {
+ target = [ targets.create-typed-target LIB : $(.project)
+ : $(build-name).$(library-id)
+ : $(sources)
+ : $(requirements)
+ <tag>@$(tag)
+ <include>$(source-path)
+ <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
+ <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+ <link>shared:<define>ZLIB_DLL
+ :
+ : <include>$(source-path) ] ;
+ }
 
+ local mt = [ new ac-library zlib : $(.project) : $(condition) ] ;
+ $(mt).set-header $(header) ;
+ $(mt).set-default-names $(names) ;
+ if $(target)
+ {
+ $(mt).set-target $(target) ;
+ }
+ targets.main-target-alternative $(mt) ;
+ } else {
+ if $(.debug)
+ {
+ ECHO "notice: [zlib] Using pre-installed library" ;
+ if $(condition)
+ {
+ ECHO "notice: [zlib] Condition" [ $(condition).raw ] ;
+ }
+ }
 
+ local mt = [ new ac-library zlib : $(.project) : $(condition) :
+ $(include-path) : $(library-path) : $(library-name) : $(root) ] ;
+ $(mt).set-header $(header) ;
+ $(mt).set-default-names $(names) ;
+ targets.main-target-alternative $(mt) ;
+ }
+ .configured.$(condition) = true ;
+}

Modified: branches/release/tools/build/v2/util/assert.jam
==============================================================================
--- branches/release/tools/build/v2/util/assert.jam (original)
+++ branches/release/tools/build/v2/util/assert.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -2,7 +2,8 @@
 # Copyright 2006 Rene Rivera
 # Copyright 2002, 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import errors ;
 import modules ;
@@ -67,14 +68,17 @@
     module [ CALLER_MODULE ]
     {
         modules.poke assert : result : [ $(1) : $(2) : $(3) : $(4) : $(5) : $(6)
- : $(7) : $(8) : $(9) ] ;
+ : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15)
+ : $(16) : $(17) : $(18) : $(19) ] ;
     }
 
     if $(result)
     {
         errors.error-skip-frames 3 assertion failure: Expected false result from
             "[" $(rule-name) [ errors.lol->list $(args) : $(2) : $(3) : $(4) :
- $(5) : $(6) : $(7) : $(8) : $(9) ] "]" : Got: "[" \"$(result)\" "]" ;
+ $(5) : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) :
+ $(14) : $(15) : $(16) : $(17) : $(18) : $(19) ] "]" : Got: "["
+ \"$(result)\" "]" ;
     }
 }
 
@@ -148,14 +152,16 @@
     module [ CALLER_MODULE ]
     {
         modules.poke assert : result : [ $(2) : $(3) : $(4) : $(5) : $(6) : $(7)
- : $(8) : $(9) ] ;
+ : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) :
+ $(16) : $(17) : $(18) : $(19) ] ;
     }
 
     if ! [ exact-equal-test $(result) : $(expected) ]
     {
         errors.error-skip-frames 3 assertion failure: "[" $(rule-name) [
             errors.lol->list $(args) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
- $(9) ] "]" : Expected: "[" \"$(expected)\" "]" : Got: "["
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17)
+ : $(18) : $(19) ] "]" : Expected: "[" \"$(expected)\" "]" : Got: "["
             \"$(result)\" "]" ;
     }
 }
@@ -163,7 +169,7 @@
 
 # Assert that EXPECTED is set-equal (i.e. duplicates and ordering are ignored)
 # to the result of calling RULE-NAME with the given arguments. Note that rules
-# called this way may accept at most 8 parameters.
+# called this way may accept at most 18 parameters.
 #
 rule result-set-equal ( expected * : rule-name args * : * )
 {
@@ -171,14 +177,16 @@
     module [ CALLER_MODULE ]
     {
         modules.poke assert : result : [ $(2) : $(3) : $(4) : $(5) : $(6) : $(7)
- : $(8) : $(9) ] ;
+ : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) :
+ $(16) : $(17) : $(18) : $(19) ] ;
     }
 
     if ! [ set-equal-test $(result) : $(expected) ]
     {
         errors.error-skip-frames 3 assertion failure: "[" $(rule-name) [
             errors.lol->list $(args) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
- $(9) ] "]" : Expected: "[" \"$(expected)\" "]" : Got: "["
+ $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17)
+ : $(18) : $(19) ] "]" : Expected: "[" \"$(expected)\" "]" : Got: "["
             \"$(result)\" "]" ;
     }
 }
@@ -205,14 +213,16 @@
     module [ CALLER_MODULE ]
     {
         modules.poke assert : result : [ $(1) : $(2) : $(3) : $(4) : $(5) : $(6)
- : $(7) : $(8) : $(9) ] ;
+ : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15)
+ : $(16) : $(17) : $(18) : $(19) ] ;
     }
 
     if ! $(result)
     {
         errors.error-skip-frames 3 assertion failure: Expected true result from
             "[" $(rule-name) [ errors.lol->list $(args) : $(2) : $(3) : $(4) :
- $(5) : $(6) : $(7) : $(8) : $(9) ] "]" ;
+ $(5) : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) : $(12) : $(13) :
+ $(14) : $(15) : $(16) : $(17) : $(18) : $(19) ] "]" ;
     }
 }
 
@@ -308,7 +318,7 @@
         $(not-equality-assert) x : $(empty-strings-x) ;
         $(not-equality-assert) "" x : $(empty-strings-x) ;
             $(equality-assert) "" "" x : $(empty-strings-x) ;
- }
+ }
 
 
     # ---------------

Modified: branches/release/tools/build/v2/util/doc.jam
==============================================================================
--- branches/release/tools/build/v2/util/doc.jam (original)
+++ branches/release/tools/build/v2/util/doc.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -246,7 +246,7 @@
 {
     print.section "General command line usage" ;
 
- print.text " bjam [options] [properties] [targets]
+ print.text " b2 [options] [properties] [targets]
 
   Options, properties and targets can be specified in any order.
       " ;
@@ -260,6 +260,7 @@
     print.list-item "-d+2 Show commands as they are executed" ;
     print.list-item "-d0 Supress all informational messages" ;
     print.list-item "-q Stop at first error" ;
+ print.list-item "--reconfigure Rerun all configuration checks" ;
     print.list-item "--debug-configuration Diagnose configuration" ;
     print.list-item "--debug-building Report which targets are built with what properties" ;
     print.list-item "--debug-generator Diagnose generator search/execution" ;
@@ -281,8 +282,8 @@
 #
 local rule print-help-usage ( )
 {
- print.section "Boost.Jam Usage"
- "bjam [ options... ] targets..."
+ print.section "Boost.Build Usage"
+ "b2 [ options... ] targets..."
         ;
     print.list-start ;
     print.list-item -a;
@@ -299,17 +300,21 @@
         Output the used build commands to file '"x"'. ;
     print.list-item -q;
         Quit as soon as a build failure is encountered. Without this option
- Boost.Jam will continue building as many targets as it can.
+ Boost.Jam will continue building as many targets as it can. ;
     print.list-item -sx=y;
         Sets a Jam variable '"x"' to the value '"y"', overriding any value that
         variable would have from the environment. ;
     print.list-item -tx;
         Rebuild the target '"x"', even if it is up-to-date. ;
     print.list-item -v;
- Display the version of bjam. ;
+ Display the version of b2. ;
     print.list-item --x;
- Any option not explicitly handled by Boost.Jam remains available to
+ Any option not explicitly handled by Boost.Build remains available to
         build scripts using the '"ARGV"' variable. ;
+ print.list-item --abbreviate-paths;
+ Use abbreviated paths for targets. ;
+ print.list-item --hash;
+ Shorten target paths by using an MD5 hash. ;
     print.list-item -dn;
         Enables output of diagnostic messages. The debug level '"n"' and all
         below it are enabled by this option. ;

Modified: branches/release/tools/build/v2/util/indirect.jam
==============================================================================
--- branches/release/tools/build/v2/util/indirect.jam (original)
+++ branches/release/tools/build/v2/util/indirect.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,7 +1,8 @@
 # Copyright 2003 Dave Abrahams
 # Copyright 2003 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 import modules ;
 import numbers ;
@@ -53,13 +54,13 @@
         frames ?= 1 ;
         # If the rule name includes a Jamfile module, grab it.
         local module-context = [ MATCH ^(Jamfile<[^>]*>)\\..* : $(rulename) ] ;
-
+
         if ! $(module-context)
- {
+ {
             # Take the first dot-separated element as module name. This disallows
             # module names with dots, but allows rule names with dots.
             module-context = [ MATCH ^([^.]*)\\..* : $(rulename) ] ;
- }
+ }
         module-context ?= [ CALLER_MODULE $(frames) ] ;
         return [ make $(rulename) $(bound-args) : $(module-context) ] ;
     }
@@ -92,8 +93,9 @@
 #
 rule call ( [indirect-rule] r args * : * )
 {
- return [ modules.call-in [ get-module $(r) ] : [ get-rule $(r) ] $(args)
- : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
+ return [ modules.call-in [ get-module $(r) ] : [ get-rule $(r) ] $(args) :
+ $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) : $(11) :
+ $(12) : $(13) : $(14) : $(15) : $(16) : $(17) : $(18) : $(19) ] ;
 }
 
 

Modified: branches/release/tools/build/v2/util/path.jam
==============================================================================
--- branches/release/tools/build/v2/util/path.jam (original)
+++ branches/release/tools/build/v2/util/path.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,10 +1,9 @@
-# Copyright Vladimir Prus 2002-2006.
-# Copyright Dave Abrahams 2003-2004.
-# Copyright Rene Rivera 2003-2006.
-#
+# Copyright 2002-2006. Vladimir Prus
+# Copyright 2003-2004. Dave Abrahams
+# Copyright 2003-2006. Rene Rivera
 # 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 accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 # Performs various path manipulations. Paths are always in a 'normalized'
 # representation. In it, a path may be either:
@@ -17,12 +16,10 @@
 # beginning, and it never ends in slash, except for path consisting of slash
 # only.
 
-import errors ;
 import modules ;
 import regex ;
 import sequence ;
 import set ;
-import version ;
 
 
 os = [ modules.peek : OS ] ;
@@ -124,6 +121,7 @@
     }
     else
     {
+ import errors ;
         errors.error "Path '$(path)' has no parent" ;
     }
 }
@@ -140,13 +138,13 @@
     }
     else
     {
- local tokens = [ regex.split $(path) "/" ] ;
+ local tokens = [ regex.split $(path) / ] ;
         local tokens2 ;
         for local i in $(tokens)
         {
             tokens2 += .. ;
         }
- return [ sequence.join $(tokens2) : "/" ] ;
+ return [ sequence.join $(tokens2) : / ] ;
     }
 }
 
@@ -166,30 +164,11 @@
         {
             if [ is-rooted $(e) ]
             {
+ import errors ;
                 errors.error only the first element may be rooted ;
             }
         }
- if [ version.check-jam-version 3 1 17 ]
- {
- return [ NORMALIZE_PATH "$(elements)" ] ;
- }
- else
- {
- # Boost Jam prior to version 3.1.17 had problems with its
- # NORMALIZE_PATH rule in case you passed it a leading backslash
- # instead of a slash, in some cases when you sent it an empty
- # initial path element and possibly some others. At least some of
- # those cases were being hit and relied upon when calling this rule
- # from the path.make-NT rule.
- if ! $(elements[1]) && $(elements[2])
- {
- return [ NORMALIZE_PATH "/" "$(elements[2-])" ] ;
- }
- else
- {
- return [ NORMALIZE_PATH "$(elements)" ] ;
- }
- }
+ return [ NORMALIZE_PATH "$(elements)" ] ;
     }
 }
 
@@ -320,13 +299,13 @@
 rule all-parents ( path : upper_limit ? : cwd ? )
 {
     cwd ?= [ pwd ] ;
- local path_ele = [ regex.split [ root $(path) $(cwd) ] "/" ] ;
+ local path_ele = [ regex.split [ root $(path) $(cwd) ] / ] ;
 
     if ! $(upper_limit)
     {
         upper_limit = / ;
     }
- local upper_ele = [ regex.split [ root $(upper_limit) $(cwd) ] "/" ] ;
+ local upper_ele = [ regex.split [ root $(upper_limit) $(cwd) ] / ] ;
 
     # Leave only elements in 'path_ele' below 'upper_ele'.
     while $(path_ele) && ( $(upper_ele[1]) = $(path_ele[1]) )
@@ -338,9 +317,10 @@
     # Have all upper elements been removed ?
     if $(upper_ele)
     {
+ import errors ;
         errors.error "$(upper_limit) is not prefix of $(path)" ;
     }
-
+
     # Create the relative paths to parents, number of elements in 'path_ele'.
     local result ;
     for local i in $(path_ele)
@@ -352,8 +332,8 @@
 }
 
 
-# Search for 'pattern' in parent directories of 'dir', up till and including
-# 'upper_limit', if it is specified, or till the filesystem root otherwise.
+# Search for 'pattern' in parent directories of 'dir', up to and including
+# 'upper_limit', if it is specified, or up to the filesystem root otherwise.
 #
 rule glob-in-parents ( dir : patterns + : upper-limit ? )
 {
@@ -407,13 +387,14 @@
                 }
                 else
                 {
+ import errors ;
                     errors.error $(child) is not a subdir of $(parent) ;
- }
+ }
             }
             else
             {
- return [ join $(split2) ] ;
- }
+ return [ join $(split2) ] ;
+ }
         }
         else
         {
@@ -423,7 +404,7 @@
 }
 
 
-# Returns the minimal path to path2 that is relative path1.
+# Returns the minimal path to path2 that is relative to path1.
 #
 rule relative-to ( path1 path2 )
 {
@@ -448,8 +429,8 @@
 }
 
 
-# Returns the list of paths which are used by the operating system for looking
-# up programs.
+# Returns the list of paths used by the operating system for looking up
+# programs.
 #
 rule programs-path ( )
 {
@@ -465,6 +446,7 @@
     return $(result) ;
 }
 
+
 rule makedirs ( path )
 {
     local result = true ;
@@ -472,17 +454,19 @@
     if ! [ exists $(native) ]
     {
         if [ makedirs [ parent $(path) ] ]
- {
+ {
             if ! [ MAKEDIR $(native) ]
             {
+ import errors ;
                 errors.error "Could not create directory '$(path)'" ;
                 result = ;
             }
- }
- }
+ }
+ }
     return $(result) ;
 }
 
+
 # Converts native Windows paths into our internal canonic path representation.
 # Supports 'invalid' paths containing multiple successive path separator
 # characters.
@@ -492,21 +476,7 @@
 #
 rule make-NT ( native )
 {
- local result ;
-
- if [ version.check-jam-version 3 1 17 ]
- {
- result = [ NORMALIZE_PATH $(native) ] ;
- }
- else
- {
- # This old implementation is really fragile due to a not so clear way
- # NORMALIZE_PATH rule worked in Boost.Jam versions prior to 3.1.17. E.g.
- # path.join would mostly ignore empty path elements but would root the
- # joined path in case the initial two path elements were empty or some
- # similar accidental wierdness.
- result = [ path.join [ regex.split $(native) "[/\\]" ] ] ;
- }
+ local result = [ NORMALIZE_PATH $(native) ] ;
 
     # We need to add an extra '/' in front in case this is a rooted Windows path
     # starting with a drive letter and not a path separator character since the
@@ -523,17 +493,12 @@
 
 rule native-NT ( path )
 {
- local result ;
- if [ is-rooted $(path) ] && ! [ regex.match "^/(.:)" : $(path) ]
- {
- result = $(path) ;
- }
- else
+ local remove-slash = [ MATCH "^/(.:.*)" : $(path) ] ;
+ if $(remove-slash)
     {
- result = [ MATCH "^/?(.*)" : $(path) ] ;
+ path = $(remove-slash) ;
     }
- result = [ sequence.join [ regex.split $(result) "/" ] : "\\" ] ;
- return $(result) ;
+ return [ regex.replace $(path) / \\ ] ;
 }
 
 
@@ -542,6 +507,7 @@
     # VP: I have no idea now 'native' can be empty here! But it can!
     if ! $(native)
     {
+ import errors ;
         errors.error "Empty path passed to 'make-UNIX'" ;
     }
     else
@@ -583,7 +549,8 @@
 #
 rule split-path-VMS ( native )
 {
- local matches = [ MATCH ([a-zA-Z0-9_-]+:)?(\\[[^\]]*\\])?(.*)?$ : $(native) ] ;
+ local matches = [ MATCH ([a-zA-Z0-9_-]+:)?(\\[[^\]]*\\])?(.*)?$ : $(native)
+ ] ;
     local device = $(matches[1]) ;
     local dir = $(matches[2]) ;
     local file = $(matches[3]) ;
@@ -604,6 +571,7 @@
 {
     if [ MATCH ^(\\[[a-zA-Z0-9]) : $(native) ]
     {
+ import errors ;
         errors.error "Can't handle default-device absolute paths: " $(native) ;
     }
 
@@ -695,10 +663,9 @@
     #
     # This is no exact science, just guess work:
     #
- # If the last part of the current path spec
- # includes some chars, followed by a dot,
- # optionally followed by more chars -
- # then it is a file (keep your fingers crossed).
+ # If the last part of the current path spec includes some chars, followed by
+ # a dot, optionally followed by more chars - then it is a file (keep your
+ # fingers crossed).
     #
     split = [ regex.split $(dir) / ] ;
     local maybe_file = $(split[-1]) ;
@@ -736,6 +703,9 @@
     return $(native) ;
 }
 
+# Remove one level of indirection
+IMPORT $(__name__) : make-$(os) native-$(os) : $(__name__) : make native ;
+EXPORT $(__name__) : make native ;
 
 rule __test__ ( )
 {
@@ -800,8 +770,10 @@
     local CWD = "/home/ghost/build" ;
     assert.result : all-parents . : . : $(CWD) ;
     assert.result . .. ../.. ../../.. : all-parents "Jamfile" : "" : $(CWD) ;
- assert.result foo . .. ../.. ../../.. : all-parents "foo/Jamfile" : "" : $(CWD) ;
- assert.result ../Work .. ../.. ../../.. : all-parents "../Work/Jamfile" : "" : $(CWD) ;
+ assert.result foo . .. ../.. ../../.. : all-parents "foo/Jamfile" : "" :
+ $(CWD) ;
+ assert.result ../Work .. ../.. ../../.. : all-parents "../Work/Jamfile" : ""
+ : $(CWD) ;
 
     local CWD = "/home/ghost" ;
     assert.result . .. : all-parents "Jamfile" : "/home" : $(CWD) ;
@@ -813,68 +785,70 @@
     local save-os = [ modules.peek path : os ] ;
     modules.poke path : os : NT ;
 
- assert.result "foo/bar/giz" : make "foo/bar/giz" ;
- assert.result "foo/bar/giz" : make "foo\\bar\\giz" ;
- assert.result "foo" : make "foo/" ;
- assert.result "foo" : make "foo\\" ;
- assert.result "foo" : make "foo/." ;
- assert.result "foo" : make "foo/bar/.." ;
- assert.result "foo" : make "foo/bar/../" ;
- assert.result "foo" : make "foo/bar/..\\" ;
- assert.result "foo/bar" : make "foo/././././bar" ;
- assert.result "/foo" : make "\\foo" ;
- assert.result "/D:/My Documents" : make "D:\\My Documents" ;
- assert.result "/c:/boost/tools/build/new/project.jam" : make "c:\\boost\\tools\\build\\test\\..\\new\\project.jam" ;
-
- # Test processing 'invalid' paths containing multiple successive path
+ assert.result "foo/bar/giz" : make-NT "foo/bar/giz" ;
+ assert.result "foo/bar/giz" : make-NT "foo\\bar\\giz" ;
+ assert.result "foo" : make-NT "foo/" ;
+ assert.result "foo" : make-NT "foo\\" ;
+ assert.result "foo" : make-NT "foo/." ;
+ assert.result "foo" : make-NT "foo/bar/.." ;
+ assert.result "foo" : make-NT "foo/bar/../" ;
+ assert.result "foo" : make-NT "foo/bar/..\\" ;
+ assert.result "foo/bar" : make-NT "foo/././././bar" ;
+ assert.result "/foo" : make-NT "\\foo" ;
+ assert.result "/D:/My Documents" : make-NT "D:\\My Documents" ;
+ assert.result "/c:/boost/tools/build/new/project.jam" : make-NT
+ "c:\\boost\\tools\\build\\test\\..\\new\\project.jam" ;
+
+ # Test processing 'invalid' paths containing multiple successive path
     # separators.
- assert.result "foo" : make "foo//" ;
- assert.result "foo" : make "foo///" ;
- assert.result "foo" : make "foo\\\\" ;
- assert.result "foo" : make "foo\\\\\\" ;
- assert.result "/foo" : make "//foo" ;
- assert.result "/foo" : make "///foo" ;
- assert.result "/foo" : make "\\\\foo" ;
- assert.result "/foo" : make "\\\\\\foo" ;
- assert.result "/foo" : make "\\/\\/foo" ;
- assert.result "foo/bar" : make "foo//\\//\\\\bar//\\//\\\\\\//\\//\\\\" ;
- assert.result "foo" : make "foo/bar//.." ;
- assert.result "foo/bar" : make "foo/bar/giz//.." ;
- assert.result "foo/giz" : make "foo//\\//\\\\bar///\\\\//\\\\////\\/..///giz\\//\\\\\\//\\//\\\\" ;
- assert.result "../../../foo" : make "..///.//..///.//..////foo///" ;
+ assert.result "foo" : make-NT "foo//" ;
+ assert.result "foo" : make-NT "foo///" ;
+ assert.result "foo" : make-NT "foo\\\\" ;
+ assert.result "foo" : make-NT "foo\\\\\\" ;
+ assert.result "/foo" : make-NT "//foo" ;
+ assert.result "/foo" : make-NT "///foo" ;
+ assert.result "/foo" : make-NT "\\\\foo" ;
+ assert.result "/foo" : make-NT "\\\\\\foo" ;
+ assert.result "/foo" : make-NT "\\/\\/foo" ;
+ assert.result "foo/bar" : make-NT "foo//\\//\\\\bar//\\//\\\\\\//\\//\\\\" ;
+ assert.result "foo" : make-NT "foo/bar//.." ;
+ assert.result "foo/bar" : make-NT "foo/bar/giz//.." ;
+ assert.result "foo/giz" : make-NT
+ "foo//\\//\\\\bar///\\\\//\\\\////\\/..///giz\\//\\\\\\//\\//\\\\" ;
+ assert.result "../../../foo" : make-NT "..///.//..///.//..////foo///" ;
 
- # Test processing 'invalid' rooted paths with too many '..' path elements
+ # Test processing 'invalid' rooted paths with too many '..' path elements
     # that would place them before the root.
- assert.result : make "/.." ;
- assert.result : make "/../" ;
- assert.result : make "/../." ;
- assert.result : make "/.././" ;
- assert.result : make "/foo/../bar/giz/.././././../../." ;
- assert.result : make "/foo/../bar/giz/.././././../.././" ;
- assert.result : make "//foo/../bar/giz/.././././../../." ;
- assert.result : make "//foo/../bar/giz/.././././../.././" ;
- assert.result : make "\\\\foo/../bar/giz/.././././../../." ;
- assert.result : make "\\\\foo/../bar/giz/.././././../.././" ;
- assert.result : make "/..///.//..///.//..////foo///" ;
-
- assert.result "foo\\bar\\giz" : native "foo/bar/giz" ;
- assert.result "foo" : native "foo" ;
- assert.result "\\foo" : native "/foo" ;
- assert.result "D:\\My Documents\\Work" : native "/D:/My Documents/Work" ;
+ assert.result : make-NT "/.." ;
+ assert.result : make-NT "/../" ;
+ assert.result : make-NT "/../." ;
+ assert.result : make-NT "/.././" ;
+ assert.result : make-NT "/foo/../bar/giz/.././././../../." ;
+ assert.result : make-NT "/foo/../bar/giz/.././././../.././" ;
+ assert.result : make-NT "//foo/../bar/giz/.././././../../." ;
+ assert.result : make-NT "//foo/../bar/giz/.././././../.././" ;
+ assert.result : make-NT "\\\\foo/../bar/giz/.././././../../." ;
+ assert.result : make-NT "\\\\foo/../bar/giz/.././././../.././" ;
+ assert.result : make-NT "/..///.//..///.//..////foo///" ;
+
+ assert.result "foo\\bar\\giz" : native-NT "foo/bar/giz" ;
+ assert.result "foo" : native-NT "foo" ;
+ assert.result "\\foo" : native-NT "/foo" ;
+ assert.result "D:\\My Documents\\Work" : native-NT "/D:/My Documents/Work" ;
 
     modules.poke path : os : UNIX ;
 
- assert.result "foo/bar/giz" : make "foo/bar/giz" ;
- assert.result "/sub1" : make "/sub1/." ;
- assert.result "/sub1" : make "/sub1/sub2/.." ;
- assert.result "sub1" : make "sub1/." ;
- assert.result "sub1" : make "sub1/sub2/.." ;
- assert.result "/foo/bar" : native "/foo/bar" ;
+ assert.result "foo/bar/giz" : make-UNIX "foo/bar/giz" ;
+ assert.result "/sub1" : make-UNIX "/sub1/." ;
+ assert.result "/sub1" : make-UNIX "/sub1/sub2/.." ;
+ assert.result "sub1" : make-UNIX "sub1/." ;
+ assert.result "sub1" : make-UNIX "sub1/sub2/.." ;
+ assert.result "/foo/bar" : native-UNIX "/foo/bar" ;
 
     modules.poke path : os : VMS ;
 
     #
- # Don't really need to poke os before these
+ # Do not really need to poke os before these
     #
     assert.result "disk:" "[dir]" "file" : split-path-VMS "disk:[dir]file" ;
     assert.result "disk:" "[dir]" "" : split-path-VMS "disk:[dir]" ;
@@ -896,39 +870,41 @@
     #
     # Make portable paths
     #
- assert.result "/disk:" : make "disk:" ;
- assert.result "foo/bar/giz" : make "[.foo.bar.giz]" ;
- assert.result "foo" : make "[.foo]" ;
- assert.result "foo" : make "[.foo.bar.-]" ;
- assert.result ".." : make "[.-]" ;
- assert.result ".." : make "[-]" ;
- assert.result "." : make "[]" ;
- assert.result "giz.h" : make "giz.h" ;
- assert.result "foo/bar/giz.h" : make "[.foo.bar]giz.h" ;
- assert.result "/disk:/my_docs" : make "disk:[my_docs]" ;
- assert.result "/disk:/boost/tools/build/new/project.jam" : make "disk:[boost.tools.build.test.-.new]project.jam" ;
-
- #
- # Special case (adds '.' to end of file w/o extension to
- # disambiguate from directory in portable path spec).
- #
- assert.result "Jamfile." : make "Jamfile" ;
- assert.result "dir/Jamfile." : make "[.dir]Jamfile" ;
- assert.result "/disk:/dir/Jamfile." : make "disk:[dir]Jamfile" ;
+ assert.result "/disk:" : make-VMS "disk:" ;
+ assert.result "foo/bar/giz" : make-VMS "[.foo.bar.giz]" ;
+ assert.result "foo" : make-VMS "[.foo]" ;
+ assert.result "foo" : make-VMS "[.foo.bar.-]" ;
+ assert.result ".." : make-VMS "[.-]" ;
+ assert.result ".." : make-VMS "[-]" ;
+ assert.result "." : make-VMS "[]" ;
+ assert.result "giz.h" : make-VMS "giz.h" ;
+ assert.result "foo/bar/giz.h" : make-VMS "[.foo.bar]giz.h" ;
+ assert.result "/disk:/my_docs" : make-VMS "disk:[my_docs]" ;
+ assert.result "/disk:/boost/tools/build/new/project.jam" : make-VMS
+ "disk:[boost.tools.build.test.-.new]project.jam" ;
+
+ #
+ # Special case (adds '.' to end of file w/o extension to disambiguate from
+ # directory in portable path spec)
+ #
+ assert.result "Jamfile." : make-VMS "Jamfile" ;
+ assert.result "dir/Jamfile." : make-VMS "[.dir]Jamfile" ;
+ assert.result "/disk:/dir/Jamfile." : make-VMS "disk:[dir]Jamfile" ;
 
     #
     # Make native paths
     #
- assert.result "disk:" : native "/disk:" ;
- assert.result "[.foo.bar.giz]" : native "foo/bar/giz" ;
- assert.result "[.foo]" : native "foo" ;
- assert.result "[.-]" : native ".." ;
- assert.result "[.foo.-]" : native "foo/.." ;
- assert.result "[]" : native "." ;
- assert.result "disk:[my_docs.work]" : native "/disk:/my_docs/work" ;
- assert.result "giz.h" : native "giz.h" ;
- assert.result "disk:Jamfile." : native "/disk:Jamfile." ;
- assert.result "disk:[my_docs.work]Jamfile." : native "/disk:/my_docs/work/Jamfile." ;
+ assert.result "disk:" : native-VMS "/disk:" ;
+ assert.result "[.foo.bar.giz]" : native-VMS "foo/bar/giz" ;
+ assert.result "[.foo]" : native-VMS "foo" ;
+ assert.result "[.-]" : native-VMS ".." ;
+ assert.result "[.foo.-]" : native-VMS "foo/.." ;
+ assert.result "[]" : native-VMS "." ;
+ assert.result "disk:[my_docs.work]" : native-VMS "/disk:/my_docs/work" ;
+ assert.result "giz.h" : native-VMS "giz.h" ;
+ assert.result "disk:Jamfile." : native-VMS "/disk:Jamfile." ;
+ assert.result "disk:[my_docs.work]Jamfile." : native-VMS
+ "/disk:/my_docs/work/Jamfile." ;
 
     modules.poke path : os : $(save-os) ;
 }

Modified: branches/release/tools/build/v2/util/print.jam
==============================================================================
--- branches/release/tools/build/v2/util/print.jam (original)
+++ branches/release/tools/build/v2/util/print.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -1,8 +1,8 @@
-# Copyright 2003 Douglas Gregor
-# Copyright 2002, 2003, 2005 Rene Rivera
-# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
-# 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)
+# Copyright 2003 Douglas Gregor
+# Copyright 2002, 2003, 2005 Rene Rivera
+# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
+# 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)
 
 # Utilities for generating format independent output. Using these
 # will help in generation of documentation in at minimum plain/console
@@ -242,7 +242,7 @@
         local t = "" ;
         # divide s into the first X characters and the rest
         s = [ MATCH "^($(char-match))(.*)" : $(text) ] ;
-
+
         if $(s[2])
         {
             # split the first half at a space
@@ -252,12 +252,12 @@
         {
             t = $(s) ;
         }
-
+
         if ! $(t[2])
         {
             t += "" ;
         }
-
+
         text = $(t[2])$(s[2]) ;
         lines += $(t[1]) ;
     }
@@ -270,9 +270,9 @@
 # split them with <br>.
 #
 rule lines (
- text * # The lines of text.
- : indent ? # Optional indentation prepended to each line after the first one.
- outdent ? # Optional indentation to prepend to the first line.
+ text * # The lines of text.
+ : indent ? # Optional indentation prepended to each line after the first.
+ outdent ? # Optional indentation to prepend to the first line.
 )
 {
     text ?= "" ;
@@ -307,9 +307,10 @@
 # output using this rule.
 #
 rule text (
- strings * # The strings of text to output.
- : overwrite ? # true to overwrite the output (if it is a file)
- : prefix-body-suffix ? # Indication to output prefix, body, or suffix (for a file).
+ strings * # The strings of text to output.
+ : overwrite ? # True to overwrite the output (if it is a file).
+ : prefix-body-suffix ? # Indication to output prefix, body, or suffix (for
+ # a file).
 )
 {
     prefix-body-suffix ?= body ;
@@ -333,7 +334,7 @@
         $(output-target).text-prefix = ;
         $(output-target).text-body = ;
         $(output-target).text-suffix = ;
-
+
         nl on $(output-target) = "
 " ;
         text-redirect on $(output-target) = ">>" ;
@@ -342,7 +343,7 @@
             text-redirect on $(output-target) = ">" ;
         }
         text-content on $(output-target) = ;
-
+
         text-action $(output-target) ;
 
         if $(overwrite) && $(output-target) != console
@@ -412,11 +413,10 @@
 }
 
 
-# The following code to update print targets when their contents
-# change is a horrible hack. It basically creates a target which
-# binds to this file (print.jam) and installs a scanner on it
-# which reads the target and compares its contents to the new
-# contents that we're writing.
+# The following code to update print targets when their contents change is a
+# horrible hack. It basically creates a target which binds to this file
+# (print.jam) and installs a scanner on it which reads the target and compares
+# its contents to the new contents that we are writing.
 #
 rule check-for-update ( target )
 {
@@ -429,7 +429,7 @@
     ISFILE $(dependency-target) ;
     NOUPDATE $(dependency-target) ;
     base on $(dependency-target) = $(target) ;
- scanner.install $(scanner) : $(dependency-target) none ;
+ scanner.install $(scanner) : $(dependency-target) ;
     return $(dependency-target) ;
 }
 
@@ -475,7 +475,7 @@
 rule __test__ ( )
 {
     import assert ;
-
+
     assert.result one two three : split-at-words one two three : 5 ;
     assert.result "one two" three : split-at-words one two three : 8 ;
     assert.result "one two" three : split-at-words one two three : 9 ;

Modified: branches/release/tools/build/v2/util/regex.jam
==============================================================================
--- branches/release/tools/build/v2/util/regex.jam (original)
+++ branches/release/tools/build/v2/util/regex.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -3,7 +3,8 @@
 # Copyright 2003 Rene Rivera
 # Copyright 2002, 2003, 2004, 2005 Vladimir Prus
 # 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)
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
 
 #
 # Returns a list of the following substrings:
@@ -36,6 +37,10 @@
     return $(s) $(result) ;
 }
 
+if [ HAS_NATIVE_RULE regex : split : 1 ]
+{
+ NATIVE_RULE regex : split ;
+}
 
 # Returns the concatenated results of Applying regex.split to every element of
 # the list using the separator pattern.
@@ -63,7 +68,7 @@
 
 # Matches all elements of 'list' agains the 'pattern' and returns a list of
 # elements indicated by indices of all successful matches. If 'indices' is
-# omitted returns a list of first paranthethised groups of all successful
+# omitted returns a list of first parenthesised groups of all successful
 # matches.
 #
 rule transform ( list * : pattern : indices * )
@@ -133,6 +138,11 @@
     return $(result) ;
 }
 
+if [ HAS_NATIVE_RULE regex : replace : 1 ]
+{
+ NATIVE_RULE regex : replace ;
+}
+
 
 # Replaces occurrences of a match string in a given list of strings and returns
 # a list of new strings. The match string can be a regex expression.

Modified: branches/release/tools/build/v2/util/sequence.jam
==============================================================================
--- branches/release/tools/build/v2/util/sequence.jam (original)
+++ branches/release/tools/build/v2/util/sequence.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -50,6 +50,10 @@
     return $(result) ;
 }
 
+if [ HAS_NATIVE_RULE sequence : transform : 1 ]
+{
+ NATIVE_RULE sequence : transform ;
+}
 
 rule reverse ( s * )
 {

Modified: branches/release/tools/build/v2/util/utility.jam
==============================================================================
--- branches/release/tools/build/v2/util/utility.jam (original)
+++ branches/release/tools/build/v2/util/utility.jam 2013-05-21 00:14:18 EDT (Tue, 21 May 2013)
@@ -5,7 +5,6 @@
 # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 
 import "class" : is-instance ;
-import errors ;
 
 
 # For all elements of 'list' which do not already have 'suffix', add 'suffix'.
@@ -114,9 +113,12 @@
     for local name in $(names)
     {
         local stripped = [ MATCH ^<(.*)>$ : $(name) ] ;
- if ! $(stripped)
+ if ! $(stripped)-defined
         {
- errors.error "in ungrist $(names) : $(name) is not of the form <.*>" ;
+ import errors ;
+ local quoted-names = \"$(names)\" ;
+ errors.error "in" ungrist $(quoted-names:J=" "): \"$(name)\" is not
+ of the form <.*> ;
         }
         result += $(stripped) ;
     }
@@ -174,6 +176,9 @@
 
     assert.result : unquote ;
     assert.result "" : unquote "" ;
+ assert.result "" : unquote \"\" ;
+ assert.result \" : unquote \"\"\" ;
+ assert.result \"\" : unquote \"\"\"\" ;
     assert.result foo : unquote foo ;
     assert.result \"foo : unquote \"foo ;
     assert.result foo\" : unquote foo\" ;
@@ -181,6 +186,7 @@
     assert.result \"foo\" : unquote \"\"foo\"\" ;
 
     assert.result : ungrist ;
+ assert.result "" : ungrist <> ;
     assert.result foo : ungrist <foo> ;
     assert.result <foo> : ungrist <<foo>> ;
     assert.result foo bar : ungrist <foo> <bar> ;
@@ -189,47 +195,41 @@
     {
         ungrist "" ;
     }
- catch "in ungrist : is not of the form <.*>" ;
-
- try ;
- {
- ungrist <> ;
- }
- catch "in ungrist <> : <> is not of the form <.*>" ;
+ catch "in" ungrist \"\": \"\" is not of the form <.*> ;
 
     try ;
     {
         ungrist foo ;
     }
- catch "in ungrist foo : foo is not of the form <.*>" ;
+ catch "in" ungrist \"foo\": \"foo\" is not of the form <.*> ;
 
     try ;
     {
         ungrist <foo ;
     }
- catch "in ungrist <foo : <foo is not of the form <.*>" ;
+ catch "in" ungrist \"<foo\": \"<foo\" is not of the form <.*> ;
 
     try ;
     {
         ungrist foo> ;
     }
- catch "in ungrist foo> : foo> is not of the form <.*>" ;
+ catch "in" ungrist \"foo>\": \"foo>\" is not of the form <.*> ;
 
     try ;
     {
         ungrist foo bar ;
     }
- catch "in ungrist foo : foo is not of the form <.*>" ;
+ catch "in" ungrist "\"foo\" \"bar\"": \"foo\" is not of the form <.*> ;
 
     try ;
     {
         ungrist foo <bar> ;
     }
- catch "in ungrist foo : foo is not of the form <.*>" ;
+ catch "in" ungrist "\"foo\" \"<bar>\"": \"foo\" is not of the form <.*> ;
 
     try ;
     {
         ungrist <foo> bar ;
     }
- catch "in ungrist bar : bar is not of the form <.*>" ;
+ catch "in" ungrist "\"<foo>\" \"bar\"": \"bar\" is not of the form <.*> ;
 }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk