summaryrefslogtreecommitdiff
path: root/tools/build/v2
diff options
context:
space:
mode:
Diffstat (limited to 'tools/build/v2')
-rw-r--r--tools/build/v2/Jamroot.jam2
-rw-r--r--tools/build/v2/bootstrap.bat2
-rw-r--r--tools/build/v2/build/engine.py11
-rw-r--r--tools/build/v2/build/feature.py4
-rw-r--r--tools/build/v2/build/generators.jam76
-rw-r--r--tools/build/v2/build/generators.py36
-rw-r--r--tools/build/v2/build/project.jam201
-rw-r--r--tools/build/v2/build/property-set.jam184
-rw-r--r--tools/build/v2/build/property.py4
-rw-r--r--tools/build/v2/build/targets.jam2
-rw-r--r--tools/build/v2/build/targets.py3
-rw-r--r--tools/build/v2/build/toolset.jam75
-rw-r--r--tools/build/v2/build/toolset.py11
-rw-r--r--tools/build/v2/build/type.py2
-rw-r--r--tools/build/v2/build/version.jam2
-rw-r--r--tools/build/v2/build_system.py37
-rw-r--r--tools/build/v2/doc/src/abstract-target.xml126
-rw-r--r--tools/build/v2/doc/src/basic-target.xml96
-rw-r--r--tools/build/v2/doc/src/catalog.xml9
-rw-r--r--tools/build/v2/doc/src/extending.xml71
-rw-r--r--tools/build/v2/doc/src/faq.xml18
-rw-r--r--tools/build/v2/doc/src/howto.xml2
-rw-r--r--tools/build/v2/doc/src/install.xml8
-rw-r--r--tools/build/v2/doc/src/main-target.xml59
-rw-r--r--tools/build/v2/doc/src/overview.xml176
-rw-r--r--tools/build/v2/doc/src/path.xml248
-rw-r--r--tools/build/v2/doc/src/project-target.xml144
-rw-r--r--tools/build/v2/doc/src/property-set.xml128
-rw-r--r--tools/build/v2/doc/src/reference.xml286
-rw-r--r--tools/build/v2/doc/src/standalone.xml2
-rw-r--r--tools/build/v2/doc/src/tasks.xml178
-rw-r--r--tools/build/v2/doc/src/tutorial.xml119
-rw-r--r--tools/build/v2/doc/src/type.xml236
-rw-r--r--tools/build/v2/doc/src/typed-target.xml106
-rw-r--r--tools/build/v2/doc/src/userman.xml2
-rw-r--r--tools/build/v2/engine/build.bat42
-rw-r--r--tools/build/v2/engine/build.jam109
-rwxr-xr-xtools/build/v2/engine/build.sh6
-rw-r--r--tools/build/v2/engine/build_vms.com105
-rw-r--r--tools/build/v2/engine/builtins.c924
-rw-r--r--tools/build/v2/engine/builtins.h81
-rw-r--r--tools/build/v2/engine/class.c96
-rw-r--r--tools/build/v2/engine/class.h3
-rw-r--r--tools/build/v2/engine/command.c34
-rw-r--r--tools/build/v2/engine/command.h11
-rw-r--r--tools/build/v2/engine/compile.c1163
-rw-r--r--tools/build/v2/engine/compile.h29
-rw-r--r--tools/build/v2/engine/constants.c183
-rw-r--r--tools/build/v2/engine/constants.h72
-rw-r--r--tools/build/v2/engine/debug.c35
-rw-r--r--tools/build/v2/engine/debug.h9
-rw-r--r--tools/build/v2/engine/execcmd.h10
-rw-r--r--tools/build/v2/engine/execmac.c69
-rw-r--r--tools/build/v2/engine/execnt.c65
-rw-r--r--tools/build/v2/engine/execunix.c34
-rw-r--r--tools/build/v2/engine/execvms.c161
-rw-r--r--tools/build/v2/engine/expand.c733
-rw-r--r--tools/build/v2/engine/expand.h14
-rw-r--r--tools/build/v2/engine/filemac.c175
-rw-r--r--tools/build/v2/engine/filent.c96
-rw-r--r--tools/build/v2/engine/fileos2.c138
-rw-r--r--tools/build/v2/engine/filesys.c52
-rw-r--r--tools/build/v2/engine/filesys.h21
-rw-r--r--tools/build/v2/engine/fileunix.c84
-rw-r--r--tools/build/v2/engine/filevms.c327
-rw-r--r--tools/build/v2/engine/frames.c3
-rw-r--r--tools/build/v2/engine/frames.h14
-rw-r--r--tools/build/v2/engine/function.c4553
-rw-r--r--tools/build/v2/engine/function.h46
-rw-r--r--tools/build/v2/engine/glob.c10
-rw-r--r--tools/build/v2/engine/hash.c333
-rw-r--r--tools/build/v2/engine/hash.h65
-rw-r--r--tools/build/v2/engine/hcache.c334
-rw-r--r--tools/build/v2/engine/hcache.h6
-rw-r--r--tools/build/v2/engine/hdrmacro.c49
-rw-r--r--tools/build/v2/engine/hdrmacro.h7
-rw-r--r--tools/build/v2/engine/headers.c61
-rw-r--r--tools/build/v2/engine/headers.h13
-rw-r--r--tools/build/v2/engine/jam.c182
-rw-r--r--tools/build/v2/engine/jam.h83
-rw-r--r--tools/build/v2/engine/jamgram.c1687
-rw-r--r--tools/build/v2/engine/jamgram.h47
-rw-r--r--tools/build/v2/engine/jamgram.y52
-rw-r--r--tools/build/v2/engine/jamgram.yy50
-rw-r--r--tools/build/v2/engine/lists.c397
-rw-r--r--tools/build/v2/engine/lists.h50
-rw-r--r--tools/build/v2/engine/make.c95
-rw-r--r--tools/build/v2/engine/make.h14
-rw-r--r--tools/build/v2/engine/make1.c249
-rw-r--r--tools/build/v2/engine/modules.c394
-rw-r--r--tools/build/v2/engine/modules.h42
-rw-r--r--tools/build/v2/engine/modules/order.c41
-rw-r--r--tools/build/v2/engine/modules/path.c10
-rw-r--r--tools/build/v2/engine/modules/property-set.c39
-rw-r--r--tools/build/v2/engine/modules/regex.c24
-rw-r--r--tools/build/v2/engine/modules/sequence.c23
-rw-r--r--tools/build/v2/engine/modules/set.c14
-rw-r--r--tools/build/v2/engine/native.c47
-rw-r--r--tools/build/v2/engine/native.h13
-rw-r--r--tools/build/v2/engine/newstr.c174
-rw-r--r--tools/build/v2/engine/newstr.h14
-rw-r--r--tools/build/v2/engine/object.c379
-rw-r--r--tools/build/v2/engine/object.h43
-rw-r--r--tools/build/v2/engine/output.c14
-rw-r--r--tools/build/v2/engine/output.h7
-rw-r--r--tools/build/v2/engine/parse.c44
-rw-r--r--tools/build/v2/engine/parse.h47
-rw-r--r--tools/build/v2/engine/patchlevel.h8
-rw-r--r--tools/build/v2/engine/pathmac.c252
-rw-r--r--tools/build/v2/engine/pathsys.h34
-rw-r--r--tools/build/v2/engine/pathunix.c338
-rw-r--r--tools/build/v2/engine/pathvms.c406
-rw-r--r--tools/build/v2/engine/pwd.c20
-rw-r--r--tools/build/v2/engine/pwd.h3
-rw-r--r--tools/build/v2/engine/regexp.c32
-rw-r--r--tools/build/v2/engine/regexp.h10
-rw-r--r--tools/build/v2/engine/rules.c350
-rw-r--r--tools/build/v2/engine/rules.h67
-rw-r--r--tools/build/v2/engine/scan.c41
-rw-r--r--tools/build/v2/engine/scan.h21
-rw-r--r--tools/build/v2/engine/search.c145
-rw-r--r--tools/build/v2/engine/search.h11
-rw-r--r--tools/build/v2/engine/subst.c57
-rw-r--r--tools/build/v2/engine/timestamp.c141
-rw-r--r--tools/build/v2/engine/timestamp.h10
-rw-r--r--tools/build/v2/engine/variable.c460
-rw-r--r--tools/build/v2/engine/variable.h23
-rw-r--r--tools/build/v2/engine/w32_getreg.c34
-rw-r--r--tools/build/v2/test/BoostBuild.py58
-rw-r--r--tools/build/v2/test/Jamrules4
-rw-r--r--tools/build/v2/test/absolute_sources.py1
-rw-r--r--tools/build/v2/test/assert-equal.jam33
-rwxr-xr-xtools/build/v2/test/builtin_echo.py30
-rwxr-xr-xtools/build/v2/test/builtin_exit.py54
-rw-r--r--tools/build/v2/test/check-arguments.jam71
-rw-r--r--tools/build/v2/test/check-jam-patches.jam293
-rw-r--r--tools/build/v2/test/check-test-tools.jam26
-rwxr-xr-xtools/build/v2/test/conditionals_multiple.py19
-rwxr-xr-xtools/build/v2/test/configuration.py8
-rw-r--r--tools/build/v2/test/core-language/test.jam1353
-rwxr-xr-xtools/build/v2/test/core_action_status.py27
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_actions_quietly.py (renamed from tools/build/v2/test/engine/actions_quietly.jam)64
-rwxr-xr-xtools/build/v2/test/core_arguments.py109
-rwxr-xr-xtools/build/v2/test/core_at_file.py75
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_bindrule.py (renamed from tools/build/v2/test/check-bindrule.jam)20
-rw-r--r--tools/build/v2/test/core_import_module.py17
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_language.py (renamed from tools/build/v2/test/project-test1/dir2/jamfile.jam)13
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_nt_line_length.py (renamed from tools/build/v2/test/test_nt_line_length.jam)21
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_option_d2.py (renamed from tools/build/v2/test/engine/option_d2.jam)65
-rwxr-xr-xtools/build/v2/test/core_option_l.py47
-rwxr-xr-xtools/build/v2/test/core_option_n.py51
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_parallel_actions.py (renamed from tools/build/v2/test/engine/parallel_actions.jam)111
-rwxr-xr-xtools/build/v2/test/core_parallel_multifile_actions_1.py68
-rwxr-xr-x[-rw-r--r--]tools/build/v2/test/core_parallel_multifile_actions_2.py (renamed from tools/build/v2/test/engine/parallel_multifile_actions_2.jam)59
-rwxr-xr-xtools/build/v2/test/core_update_now.py198
-rw-r--r--tools/build/v2/test/direct-request-test/a.cpp19
-rw-r--r--tools/build/v2/test/direct-request-test/b.cpp22
-rw-r--r--tools/build/v2/test/direct-request-test/b_inverse.cpp22
-rw-r--r--tools/build/v2/test/direct-request-test/jamfile.jam13
-rw-r--r--tools/build/v2/test/direct-request-test/jamfile2.jam9
-rw-r--r--tools/build/v2/test/direct-request-test/jamroot.jam6
-rw-r--r--tools/build/v2/test/direct_request_test.py47
-rw-r--r--tools/build/v2/test/echo_args.jam20
-rw-r--r--tools/build/v2/test/empty.jam5
-rw-r--r--tools/build/v2/test/engine/README.txt5
-rw-r--r--tools/build/v2/test/engine/action_status.jam28
-rw-r--r--tools/build/v2/test/engine/builtin_normalize_path.jam60
-rw-r--r--tools/build/v2/test/engine/builtin_shell.jam31
-rw-r--r--tools/build/v2/test/engine/builtin_w32_getregnames.jam17
-rw-r--r--tools/build/v2/test/engine/option_l.jam34
-rw-r--r--tools/build/v2/test/engine/option_n.jam44
-rw-r--r--tools/build/v2/test/engine/parallel_multifile_actions_1.jam45
-rw-r--r--tools/build/v2/test/engine/rule_param.jam60
-rw-r--r--tools/build/v2/test/engine/stress_var_expand.jam14
-rw-r--r--tools/build/v2/test/engine/target_var.jam16
-rw-r--r--tools/build/v2/test/engine/test.bat53
-rw-r--r--tools/build/v2/test/engine/test.jam91
-rwxr-xr-xtools/build/v2/test/engine/test.sh53
-rw-r--r--tools/build/v2/test/engine/var_expand.jam19
-rwxr-xr-xtools/build/v2/test/file_name_handling.py255
-rw-r--r--tools/build/v2/test/jamfile.jam11
-rw-r--r--tools/build/v2/test/load_order.py24
-rw-r--r--tools/build/v2/test/m1-01.py61
-rw-r--r--tools/build/v2/test/m1-02.py90
-rw-r--r--tools/build/v2/test/m1-03.py57
-rw-r--r--tools/build/v2/test/prebuilt/ext/jamfile2.jam4
-rw-r--r--tools/build/v2/test/prebuilt/ext/jamfile3.jam4
-rw-r--r--tools/build/v2/test/project-test1.jam18
-rw-r--r--tools/build/v2/test/project-test1/dir/jamfile.jam10
-rw-r--r--tools/build/v2/test/project-test1/dir2/jamroot.jam4
-rw-r--r--tools/build/v2/test/project-test1/jamfile.jam10
-rw-r--r--tools/build/v2/test/project-test1/jamroot.jam6
-rw-r--r--tools/build/v2/test/project-test1/project-test1.jam21
-rw-r--r--tools/build/v2/test/project-test1/readme.txt8
-rw-r--r--tools/build/v2/test/project-test1/standalone-project.jam12
-rw-r--r--tools/build/v2/test/project_test1.py78
-rw-r--r--tools/build/v2/test/recursive.jam117
-rw-r--r--tools/build/v2/test/startup_v1.py81
-rw-r--r--tools/build/v2/test/subdir1/file-to-bind1
-rw-r--r--tools/build/v2/test/test.jam30
-rw-r--r--tools/build/v2/test/test1.py4
-rw-r--r--tools/build/v2/test/test2.py4
-rw-r--r--tools/build/v2/test/test2/Jamrules0
-rw-r--r--tools/build/v2/test/test2/jamroot.jam (renamed from tools/build/v2/test/test2/jamfile.jam)3
-rw-r--r--tools/build/v2/test/test_all.py21
-rw-r--r--tools/build/v2/test/testing-primitives/boost-build.jam5
-rw-r--r--tools/build/v2/test/testing-primitives/bootstrap.jam137
-rw-r--r--tools/build/v2/test/testing_primitives.py30
-rw-r--r--tools/build/v2/test/unit-tests.jam262
-rw-r--r--tools/build/v2/test/unused.py6
-rw-r--r--tools/build/v2/test/unused/jamroot.jam15
-rw-r--r--tools/build/v2/test/v1-testing/a.cpp5
-rw-r--r--tools/build/v2/test/v1-testing/b.cpp5
-rw-r--r--tools/build/v2/test/v1-testing/boost-build.jam6
-rw-r--r--tools/build/v2/test/v1-testing/c.cpp16
-rw-r--r--tools/build/v2/test/v1-testing/jamfile.jam26
-rw-r--r--tools/build/v2/test/v1_testing.py88
-rw-r--r--tools/build/v2/test/v1_testing/Jamrules0
-rw-r--r--tools/build/v2/test/v1_testing/boost-build.jam6
-rw-r--r--tools/build/v2/test/v1_testing/foo.cpp22
-rw-r--r--tools/build/v2/test/v1_testing/jamfile.jam23
-rw-r--r--tools/build/v2/test/v1_testing/jamroot.jam5
-rw-r--r--tools/build/v2/test/v1_testing/lib-err.cpp7
-rw-r--r--tools/build/v2/test/v1_testing/lib.cpp6
-rw-r--r--tools/build/v2/tools/auto-index.jam4
-rw-r--r--tools/build/v2/tools/boostbook.jam3
-rw-r--r--tools/build/v2/tools/builtin.py131
-rw-r--r--tools/build/v2/tools/cast.jam2
-rw-r--r--tools/build/v2/tools/common.jam13
-rw-r--r--tools/build/v2/tools/common.py16
-rw-r--r--tools/build/v2/tools/cray.jam112
-rw-r--r--tools/build/v2/tools/darwin.jam27
-rw-r--r--tools/build/v2/tools/docutils.jam1
-rw-r--r--tools/build/v2/tools/gcc.jam21
-rw-r--r--tools/build/v2/tools/gcc.py14
-rw-r--r--tools/build/v2/tools/intel-win.jam4
-rw-r--r--tools/build/v2/tools/mc.py46
-rw-r--r--tools/build/v2/tools/midl.py134
-rw-r--r--tools/build/v2/tools/msvc.jam10
-rw-r--r--tools/build/v2/tools/msvc.py1198
-rw-r--r--tools/build/v2/tools/pch.py14
-rw-r--r--tools/build/v2/tools/python.jam2
-rw-r--r--tools/build/v2/tools/stage.jam2
-rw-r--r--tools/build/v2/tools/stage.py2
-rw-r--r--tools/build/v2/tools/types/__init__.py1
-rw-r--r--tools/build/v2/tools/types/cpp.py5
-rw-r--r--tools/build/v2/tools/types/preprocessed.py11
-rw-r--r--tools/build/v2/tools/unix.py8
-rw-r--r--tools/build/v2/util/doc.jam2
249 files changed, 16049 insertions, 10745 deletions
diff --git a/tools/build/v2/Jamroot.jam b/tools/build/v2/Jamroot.jam
index 11334864c2..73d86ab15b 100644
--- a/tools/build/v2/Jamroot.jam
+++ b/tools/build/v2/Jamroot.jam
@@ -38,7 +38,7 @@ package.install-data boost-build-core
[ path.glob-tree $(SELF)/build : *.jam *.py ]
[ path.glob-tree $(SELF)/kernel : *.jam *.py ]
[ path.glob-tree $(SELF)/util : *.jam *.py ]
- [ path.glob-tree $(SELF)/tools : *.jam *.py ]
+ [ path.glob-tree $(SELF)/tools : *.jam *.py *.xml *.xsl *.doxyfile *.hpp ]
$(e2)
: # What is the root of the directory
<install-source-root>.
diff --git a/tools/build/v2/bootstrap.bat b/tools/build/v2/bootstrap.bat
index 190c9283de..58f7613983 100644
--- a/tools/build/v2/bootstrap.bat
+++ b/tools/build/v2/bootstrap.bat
@@ -10,7 +10,7 @@ if exist ".\engine\bin.ntx86\bjam.exe" del engine\bin.ntx86\bjam.exe
if exist ".\engine\bin.ntx86_64\bjam.exe" del engine\bin.ntx86_64\bjam.exe
cd engine
-call .\build.bat %* > ..\..\bootstrap.log
+call .\build.bat %* > ..\bootstrap.log
@ECHO OFF
cd ..
diff --git a/tools/build/v2/build/engine.py b/tools/build/v2/build/engine.py
index be9736e06c..9e624dae82 100644
--- a/tools/build/v2/build/engine.py
+++ b/tools/build/v2/build/engine.py
@@ -20,14 +20,14 @@ class BjamAction:
self.function = function
def __call__(self, targets, sources, property_set):
- if self.function:
- self.function(targets, sources, property_set)
# Bjam actions defined from Python have only the command
# to execute, and no associated jam procedural code. So
# passing 'property_set' to it is not necessary.
bjam_interface.call("set-update-action", self.action_name,
targets, sources, [])
+ if self.function:
+ self.function(targets, sources, property_set)
class BjamNativeAction:
"""Class representing bjam action defined by Jam code.
@@ -132,7 +132,12 @@ class Engine:
bjam_flags = reduce(operator.or_,
(action_modifiers[flag] for flag in flags), 0)
- bjam_interface.define_action(action_name, command, bound_list, bjam_flags)
+ # We allow command to be empty so that we can define 'action' as pure
+ # python function that would do some conditional logic and then relay
+ # to other actions.
+ assert command or function
+ if command:
+ bjam_interface.define_action(action_name, command, bound_list, bjam_flags)
self.actions[action_name] = BjamAction(action_name, function)
diff --git a/tools/build/v2/build/feature.py b/tools/build/v2/build/feature.py
index 315a18e944..289aca14c5 100644
--- a/tools/build/v2/build/feature.py
+++ b/tools/build/v2/build/feature.py
@@ -557,10 +557,12 @@ def expand_composite(property):
result.extend(expand_composite(p))
return result
-
+@bjam_signature((['feature'], ['properties', '*']))
def get_values (feature, properties):
""" Returns all values of the given feature specified by the given property set.
"""
+ if feature[0] != '<':
+ feature = '<' + feature + '>'
result = []
for p in properties:
if get_grist (p) == feature:
diff --git a/tools/build/v2/build/generators.jam b/tools/build/v2/build/generators.jam
index 1515525f2d..333def5741 100644
--- a/tools/build/v2/build/generators.jam
+++ b/tools/build/v2/build/generators.jam
@@ -400,13 +400,13 @@ class generator
if $(self.composing)
{
- convert-multiple-sources-to-consumable-types $(project)
- : $(property-set) : $(sources) : consumed bypassed ;
+ consumed = [ convert-multiple-sources-to-consumable-types $(project)
+ : $(property-set) : $(sources) ] ;
}
else
{
- convert-to-consumable-types $(project) $(name) : $(property-set)
- : $(sources) : : consumed bypassed ;
+ consumed = [ convert-to-consumable-types $(project) $(name)
+ : $(property-set) : $(sources) ] ;
}
local result ;
@@ -579,16 +579,9 @@ class generator
: sources +
: only-one ? # Convert 'source' to only one of the source types. If
# there is more that one possibility, report an error.
- : consumed-var # Name of the variable which receives all targets which
- # can be consumed.
- bypassed-var # Name of the variable which receives all targets which
- # can not be consumed.
)
{
- # We are likely to be passed 'consumed' and 'bypassed' var names. Use
- # '_' to avoid name conflicts.
local _consumed ;
- local _bypassed ;
local missing-types ;
if $(sources[2])
@@ -599,7 +592,12 @@ class generator
}
else
{
- consume-directly $(sources) : _consumed : missing-types ;
+ local temp = [ consume-directly $(sources) ] ;
+ if $(temp[1])
+ {
+ _consumed = $(temp[1]) ;
+ }
+ missing-types = $(temp[2-]) ;
}
# No need to search for transformation if some source type has consumed
@@ -611,8 +609,6 @@ class generator
# TODO: we should check that only one source type if create of
# 'only-one' is true.
- # TODO: consider if consumed/bypassed separation should be done by
- # 'construct-types'.
if $(missing-types)
{
@@ -631,61 +627,35 @@ class generator
{
_consumed += $(t) ;
}
- else
- {
- _bypassed += $(t) ;
- }
}
}
- _consumed = [ sequence.unique $(_consumed) ] ;
- _bypassed = [ sequence.unique $(_bypassed) ] ;
-
- # Remove elements of '_bypassed' that are in '_consumed'.
-
- # Suppose the target type of current generator, X is produced from X_1
- # and X_2, which are produced from Y by one generator. When creating X_1
- # from Y, X_2 will be added to 'bypassed'. Likewise, when creating X_2
- # from Y, X_1 will be added to 'bypassed', but they are also in
- # 'consumed'. We have to remove them from bypassed, so that generators
- # up the call stack do not try to convert them.
-
- # In this particular case, X_1 instance in 'consumed' and X_1 instance
- # in 'bypassed' will be the same: because they have the same source and
- # action name, and 'virtual-target.register' will not allow two
- # different instances. Therefore, it is OK to use 'set.difference'.
-
- _bypassed = [ set.difference $(_bypassed) : $(_consumed) ] ;
-
- $(consumed-var) += $(_consumed) ;
- $(bypassed-var) += $(_bypassed) ;
+ return [ sequence.unique $(_consumed) ] ;
}
# Converts several files to consumable types. Called for composing
# generators only.
#
rule convert-multiple-sources-to-consumable-types ( project : property-set :
- sources * : consumed-var bypassed-var )
+ sources * )
{
+ local result ;
# We process each source one-by-one, trying to convert it to a usable
# type.
for local source in $(sources)
{
- local _c ;
- local _b ;
- # TODO: need to check for failure on each source.
- convert-to-consumable-types $(project) : $(property-set) : $(source)
- : true : _c _b ;
+ local _c = [ convert-to-consumable-types $(project) : $(property-set)
+ : $(source) : true ] ;
if ! $(_c)
{
generators.dout [ indent ] " failed to convert " $(source) ;
}
- $(consumed-var) += $(_c) ;
- $(bypassed-var) += $(_b) ;
+ result += $(_c) ;
}
+ return $(result) ;
}
- rule consume-directly ( source : consumed-var : missing-types-var )
+ rule consume-directly ( source )
{
local real-source-type = [ $(source).type ] ;
@@ -693,19 +663,23 @@ class generator
local source-types = $(self.source-types) ;
source-types ?= $(real-source-type) ;
+ local result = "" ;
+ local missing-types ;
+
for local st in $(source-types)
{
# The 'source' if of the right type already.
if $(real-source-type) = $(st) || [ type.is-derived
$(real-source-type) $(st) ]
{
- $(consumed-var) += $(source) ;
+ result = $(source) ;
}
else
{
- $(missing-types-var) += $(st) ;
+ missing-types += $(st) ;
}
}
+ return $(result) $(missing-types) ;
}
# Returns the class to be used to actions. Default implementation returns
@@ -1072,7 +1046,6 @@ rule construct-types ( project name ? : target-types + : property-set
: sources + )
{
local result ;
- local matched-types ;
local usage-requirements = [ property-set.empty ] ;
for local t in $(target-types)
{
@@ -1082,7 +1055,6 @@ rule construct-types ( project name ? : target-types + : property-set
{
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
result += $(r[2-]) ;
- matched-types += $(t) ;
}
}
# TODO: have to introduce parameter controlling if several types can be
diff --git a/tools/build/v2/build/generators.py b/tools/build/v2/build/generators.py
index 2c59f7ca14..7c82645388 100644
--- a/tools/build/v2/build/generators.py
+++ b/tools/build/v2/build/generators.py
@@ -400,6 +400,9 @@ class Generator:
dir = os.path.dirname(fullname)
name = os.path.basename(fullname)
+ idx = name.find(".")
+ if idx != -1:
+ name = name[:idx]
if dir and not ".." in dir and not os.path.isabs(dir):
# Relative path is always relative to the source
@@ -470,9 +473,6 @@ class Generator:
post = self.name_postfix_
for t in self.target_types_:
basename = os.path.basename(name)
- idx = basename.find(".")
- if idx != -1:
- basename = basename[:idx]
generated_name = pre[0] + basename + post[0]
generated_name = os.path.join(os.path.dirname(name), generated_name)
pre = pre[1:]
@@ -692,7 +692,7 @@ def override (overrider_id, overridee_id):
after computing the list of viable generators, before
running any of them."""
- __overrides.get(overrider_id, []).append(overridee_id)
+ __overrides.setdefault(overrider_id, []).append(overridee_id)
def __viable_source_types_real (target_type):
""" Returns a list of source type which can possibly be converted
@@ -974,7 +974,7 @@ def find_viable_generators (target_type, prop_set):
# Generators which are overriden
overriden_ids = []
-
+
for g in viable_generators:
id = g.id ()
@@ -988,13 +988,7 @@ def find_viable_generators (target_type, prop_set):
if all_overrides:
viable_generators = all_overrides
- result = []
- for g in viable_generators:
- if not g.id () in overriden_ids:
- result.append (g)
-
-
- return result
+ return [g for g in viable_generators if not g.id() in overriden_ids]
def __construct_really (project, name, target_type, prop_set, sources):
""" Attempts to construct target by finding viable generators, running them
@@ -1004,7 +998,7 @@ def __construct_really (project, name, target_type, prop_set, sources):
result = []
- project.manager ().logger ().log (__name__, "*** %d viable generators" % len (viable_generators))
+ dout(" *** %d viable generators" % len (viable_generators))
generators_that_succeeded = []
@@ -1086,4 +1080,18 @@ def construct (project, name, target_type, prop_set, sources, top_level=False):
__active_generators = saved_active
return result
-
+
+def add_usage_requirements (result, raw_properties):
+ if result:
+ if isinstance (result[0], property_set.PropertySet):
+ return (result[0].add_raw(raw_properties), result[1])
+ else:
+ return (propery_set.create(raw-properties), result)
+ #if [ class.is-a $(result[1]) : property-set ]
+ #{
+ # return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ;
+ #}
+ #else
+ #{
+ # return [ property-set.create $(raw-properties) ] $(result) ;
+ #}
diff --git a/tools/build/v2/build/project.jam b/tools/build/v2/build/project.jam
index c9967613bc..0fae4d2004 100644
--- a/tools/build/v2/build/project.jam
+++ b/tools/build/v2/build/project.jam
@@ -263,7 +263,7 @@ rule find-jamfile (
{
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'. ;
}
@@ -301,56 +301,60 @@ local rule load-jamfile (
# prevents that second attempt from messing up.
if ! $(jamfile-module) in $(.jamfile-modules)
{
- .jamfile-modules += $(jamfile-module) ;
# Initialize the Jamfile module before loading.
#
initialize $(jamfile-module) : [ path.parent $(jamfile-to-load) ]
: $(jamfile-to-load:BS) ;
- 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) ]
+ if ! $(jamfile-module) in $(.jamfile-modules)
{
- jamfile = [ find-jamfile $(dir) : no-errors ] ;
- if $(jamfile)
+ .jamfile-modules += $(jamfile-module) ;
+
+ 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) ]
{
- load-aux $(jamfile-module) : [ path.native $(jamfile) ] ;
+ jamfile = [ find-jamfile $(dir) : no-errors ] ;
+ if $(jamfile)
+ {
+ load-aux $(jamfile-module) : [ path.native $(jamfile) ] ;
+ }
}
- }
-
- # 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) ;
- }
- if $(.global-build-dir)
- {
- local id = [ attribute $(jamfile-module) id ] ;
- local project-root = [ attribute $(jamfile-module) project-root ] ;
- local location = [ attribute $(jamfile-module) location ] ;
+ # 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) ;
+ }
- if $(location) && $(project-root) = $(dir)
- {
- # This is Jamroot.
- if ! $(id)
+ if $(.global-build-dir)
{
- ECHO "warning: the --build-dir option was specified" ;
- ECHO "warning: but Jamroot at '$(dir)'" ;
- ECHO "warning: specified no project id" ;
- ECHO "warning: the --build-dir option will be ignored" ;
+ 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)
+ {
+ # This is Jamroot.
+ if ! $(id)
+ {
+ ECHO "warning: the --build-dir option was specified" ;
+ ECHO "warning: but Jamroot at '$(dir)'" ;
+ ECHO "warning: specified no project id" ;
+ ECHO "warning: the --build-dir option will be ignored" ;
+ }
+ }
}
}
}
- }
}
@@ -398,44 +402,6 @@ rule initialize (
ECHO "Initializing project '$(module-name)'" ;
}
- # 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.
- location ?= "" ;
- # Create the module for the Jamfile first.
- module $(module-name)
- {
- }
- $(module-name).attributes = [ new project-attributes $(location)
- $(module-name) ] ;
- local attributes = $($(module-name).attributes) ;
-
- if $(location)
- {
- $(attributes).set source-location : [ path.make $(location) ] : exact ;
- }
- else if ! $(module-name) in test-config site-config user-config project-config
- {
- # 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)
- {
- errors.error "Could not determine project location $(module-name)" ;
- }
- $(attributes).set source-location : $(s:D) : exact ;
- }
-
- $(attributes).set requirements : [ property-set.empty ] : exact ;
- $(attributes).set usage-requirements : [ property-set.empty ] : exact ;
-
- # Import rules common to all project modules from project-rules module,
- # defined at the end of this file.
- local rules = [ RULENAMES project-rules ] ;
- IMPORT project-rules : $(rules) : $(module-name) : $(rules) ;
-
local jamroot ;
local parent-module ;
@@ -483,33 +449,77 @@ rule initialize (
}
}
- if $(parent-module)
+ # 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.
+ location ?= "" ;
+ # Create the module for the Jamfile first.
+ module $(module-name)
{
- inherit-attributes $(module-name) : $(parent-module) ;
- $(attributes).set parent-module : $(parent-module) : exact ;
}
- if $(jamroot)
- {
- $(attributes).set project-root : $(location) : exact ;
- }
+ # load-parent can end up loading this module again.
+ # Make sure this isn't duplicated.
+ if ! $($(module-name).attributes) {
- local parent ;
- if $(parent-module)
- {
- parent = [ target $(parent-module) ] ;
- }
+ $(module-name).attributes = [ new project-attributes $(location)
+ $(module-name) ] ;
+ local attributes = $($(module-name).attributes) ;
- if ! $(.target.$(module-name))
- {
- .target.$(module-name) = [ new project-target $(module-name)
- : $(module-name) $(parent)
- : [ attribute $(module-name) requirements ] ] ;
+ if $(location)
+ {
+ $(attributes).set source-location : [ path.make $(location) ] : exact ;
+ }
+ else if ! $(module-name) in test-config site-config user-config project-config
+ {
+ # 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)
+ {
+ errors.error "Could not determine project location $(module-name)" ;
+ }
+ $(attributes).set source-location : $(s:D) : exact ;
+ }
+
+ $(attributes).set requirements : [ property-set.empty ] : exact ;
+ $(attributes).set usage-requirements : [ property-set.empty ] : exact ;
+
+ # Import rules common to all project modules from project-rules module,
+ # defined at the end of this file.
+ local rules = [ RULENAMES project-rules ] ;
+ IMPORT project-rules : $(rules) : $(module-name) : $(rules) ;
+
+ if $(parent-module)
+ {
+ inherit-attributes $(module-name) : $(parent-module) ;
+ $(attributes).set parent-module : $(parent-module) : exact ;
+ }
+
+ if $(jamroot)
+ {
+ $(attributes).set project-root : $(location) : exact ;
+ }
+
+ local parent ;
+ if $(parent-module)
+ {
+ parent = [ target $(parent-module) ] ;
+ }
- if --debug-loading in [ modules.peek : ARGV ]
+ if ! $(.target.$(module-name))
{
- ECHO "Assigned project target" $(.target.$(module-name))
- "to '$(module-name)'" ;
+ .target.$(module-name) = [ new project-target $(module-name)
+ : $(module-name) $(parent)
+ : [ attribute $(module-name) requirements ] ] ;
+
+ if --debug-loading in [ modules.peek : ARGV ]
+ {
+ ECHO "Assigned project target" $(.target.$(module-name))
+ "to '$(module-name)'" ;
+ }
}
}
@@ -1099,7 +1109,8 @@ module project-rules
rule option ( name : value )
{
- if $(__name__) != site-config && $(__name__) != user-config && $(__name__) != project-config
+ local m = [ CALLER_MODULE ] ;
+ if $(m) != site-config && $(m) != user-config && $(m) != project-config
{
import errors ;
errors.error "The 'option' rule may be used only in site-config or user-config" ;
diff --git a/tools/build/v2/build/property-set.jam b/tools/build/v2/build/property-set.jam
index 70fd90cde5..51e2b20de4 100644
--- a/tools/build/v2/build/property-set.jam
+++ b/tools/build/v2/build/property-set.jam
@@ -48,49 +48,6 @@ class property-set
{
errors.error "Invalid property: '$(p)'" ;
}
-
- local att = [ feature.attributes $(p:G) ] ;
- # A feature can be both incidental and free, in which case we add it
- # to incidental.
- if incidental in $(att)
- {
- self.incidental += $(p) ;
- }
- else if free in $(att)
- {
- self.free += $(p) ;
- }
- else
- {
- self.base += $(p) ;
- }
-
- if dependency in $(att)
- {
- self.dependency += $(p) ;
- }
- else
- {
- self.non-dependency += $(p) ;
- }
-
- if [ MATCH (:) : $(p:G=) ]
- {
- self.conditional += $(p) ;
- }
- else
- {
- self.non-conditional += $(p) ;
- }
-
- if propagated in $(att)
- {
- self.propagated += $(p) ;
- }
- if link-incompatible in $(att)
- {
- self.link-incompatible += $(p) ;
- }
}
}
@@ -110,6 +67,10 @@ class property-set
#
rule base ( )
{
+ if ! $(self.base-initialized)
+ {
+ init-base ;
+ }
return $(self.base) ;
}
@@ -117,6 +78,10 @@ class property-set
#
rule free ( )
{
+ if ! $(self.base-initialized)
+ {
+ init-base ;
+ }
return $(self.free) ;
}
@@ -124,21 +89,37 @@ class property-set
#
rule dependency ( )
{
+ if ! $(self.dependency-initialized)
+ {
+ init-dependency ;
+ }
return $(self.dependency) ;
}
rule non-dependency ( )
{
+ if ! $(self.dependency-initialized)
+ {
+ init-dependency ;
+ }
return $(self.non-dependency) ;
}
rule conditional ( )
{
+ if ! $(self.conditional-initialized)
+ {
+ init-conditional ;
+ }
return $(self.conditional) ;
}
rule non-conditional ( )
{
+ if ! $(self.conditional-initialized)
+ {
+ init-conditional ;
+ }
return $(self.non-conditional) ;
}
@@ -146,6 +127,10 @@ class property-set
#
rule incidental ( )
{
+ if ! $(self.base-initialized)
+ {
+ init-base ;
+ }
return $(self.incidental) ;
}
@@ -200,30 +185,19 @@ class property-set
{
if ! $(self.propagated-ps)
{
- self.propagated-ps = [ property-set.create $(self.propagated) ] ;
+ local result ;
+ for local p in $(self.raw)
+ {
+ if propagated in [ feature.attributes $(p:G) ]
+ {
+ result += $(p) ;
+ }
+ }
+ self.propagated-ps = [ property-set.create $(result) ] ;
}
return $(self.propagated-ps) ;
}
- rule link-incompatible ( )
- {
- if ! $(self.link-incompatible-ps)
- {
- self.link-incompatible-ps =
- [ property-set.create $(self.link-incompatible) ] ;
- }
- return $(self.link-incompatible-ps) ;
- }
-
- rule run-actions ( )
- {
- if ! $(self.run)
- {
- self.run = [ property-set.create [ feature.run-actions $(self.raw) ] ] ;
- }
- return $(self.run) ;
- }
-
rule add-defaults ( )
{
if ! $(self.defaults)
@@ -238,7 +212,7 @@ class property-set
{
if ! $(self.as-path)
{
- self.as-path = [ property.as-path $(self.base) ] ;
+ self.as-path = [ property.as-path [ base ] ] ;
}
return $(self.as-path) ;
}
@@ -303,47 +277,81 @@ class property-set
return [ add [ property-set.create $(properties) ] ] ;
}
- rule link-incompatible-with ( ps )
+ # Returns all values of 'feature'.
+ #
+ rule get ( feature )
+ {
+ if ! $(self.map-built)
+ {
+ # For each feature, create a member var and assign all values to it.
+ # Since all regular member vars start with 'self', there will be no
+ # conflicts between names.
+ self.map-built = true ;
+ for local v in $(self.raw)
+ {
+ $(v:G) += $(v:G=) ;
+ }
+ }
+ return $($(feature)) ;
+ }
+
+ # private
+
+ rule init-base ( )
{
- if ! $(.li.$(ps))
+ for local p in $(self.raw)
{
- local li1 = [ $(__name__).link-incompatible ] ;
- local li2 = [ $(ps).link-incompatible ] ;
- if [ set.equal $(li1) : $(li2) ]
+ local att = [ feature.attributes $(p:G) ] ;
+ # A feature can be both incidental and free, in which case we add it
+ # to incidental.
+ if incidental in $(att)
+ {
+ self.incidental += $(p) ;
+ }
+ else if free in $(att)
{
- .li.$(ps) = false ;
+ self.free += $(p) ;
}
else
{
- .li.$(ps) = true ;
+ self.base += $(p) ;
}
}
- if $(.li.$(ps)) = true
- {
- return true ;
- }
- else
+ self.base-initialized = true ;
+ }
+
+ rule init-dependency ( )
+ {
+ for local p in $(self.raw)
{
- return ;
+ local att = [ feature.attributes $(p:G) ] ;
+
+ if dependency in $(att)
+ {
+ self.dependency += $(p) ;
+ }
+ else
+ {
+ self.non-dependency += $(p) ;
+ }
}
+ self.dependency-initialized = true ;
}
- # Returns all values of 'feature'.
- #
- rule get ( feature )
+ rule init-conditional ( )
{
- if ! $(self.map-built)
+ for local p in $(self.raw)
{
- # For each feature, create a member var and assign all values to it.
- # Since all regular member vars start with 'self', there will be no
- # conflicts between names.
- self.map-built = true ;
- for local v in $(self.raw)
+ if [ MATCH (:) : $(p:G=) ]
{
- $(v:G) += $(v:G=) ;
+ self.conditional += $(p) ;
+ }
+ else
+ {
+ self.non-conditional += $(p) ;
}
}
- return $($(feature)) ;
+ self.conditional-initialized = true ;
}
}
diff --git a/tools/build/v2/build/property.py b/tools/build/v2/build/property.py
index c4b13dbcba..c8bbdb29f5 100644
--- a/tools/build/v2/build/property.py
+++ b/tools/build/v2/build/property.py
@@ -63,7 +63,7 @@ class Property(object):
(other._feature, other._value, other._condition))
-def create_from_string(s, allow_condition=False):
+def create_from_string(s, allow_condition=False,allow_missing_value=False):
condition = []
import types
@@ -92,7 +92,7 @@ def create_from_string(s, allow_condition=False):
f = feature.get(feature_name)
value = get_value(s)
- if not value:
+ if not value and not allow_missing_value:
get_manager().errors()("Invalid property '%s' -- no value specified" % s)
diff --git a/tools/build/v2/build/targets.jam b/tools/build/v2/build/targets.jam
index a70532ce73..12e4a5edff 100644
--- a/tools/build/v2/build/targets.jam
+++ b/tools/build/v2/build/targets.jam
@@ -936,7 +936,7 @@ rule common-properties ( build-request requirements )
{
$(key) = [ common-properties2 $(build-request) $(non-free) ] ;
}
- result = [ $($(key)).add-raw $(free) ] ;
+ return [ $($(key)).add-raw $(free) ] ;
}
diff --git a/tools/build/v2/build/targets.py b/tools/build/v2/build/targets.py
index a35612cea0..b8546809a8 100644
--- a/tools/build/v2/build/targets.py
+++ b/tools/build/v2/build/targets.py
@@ -1290,7 +1290,8 @@ class TypedTarget (BasicTarget):
def construct (self, name, source_targets, prop_set):
- r = generators.construct (self.project_, name, self.type_,
+ r = generators.construct (self.project_, os.path.splitext(name)[0],
+ self.type_,
prop_set.add_raw(['<main-target-type>' + self.type_]),
source_targets, True)
diff --git a/tools/build/v2/build/toolset.jam b/tools/build/v2/build/toolset.jam
index f2036d999c..d19be3c0b3 100644
--- a/tools/build/v2/build/toolset.jam
+++ b/tools/build/v2/build/toolset.jam
@@ -15,6 +15,7 @@ import property ;
import regex ;
import sequence ;
import set ;
+import property-set ;
.flag-no = 1 ;
@@ -320,10 +321,82 @@ rule set-target-variables-aux ( rule-or-module : property-set )
return $(result) ;
}
+rule relevant-features ( rule-or-module )
+{
+ local result ;
+ if ! $(.relevant-features.$(rule-or-module))
+ {
+ for local f in $(.$(rule-or-module).flags)
+ {
+ local condition = $(.$(rule-or-module).condition.$(f)) ;
+ local values = $(.$(rule-or-module).values.$(f)) ;
+
+ for local c in $(condition)
+ {
+ for local p in [ feature.split $(c) ]
+ {
+ if $(p:G)
+ {
+ result += $(p:G) ;
+ }
+ else
+ {
+ local temp = [ feature.expand-subfeatures $(p) ] ;
+ result += $(temp:G) ;
+ }
+ }
+ }
+
+ for local v in $(values)
+ {
+ if $(v:G)
+ {
+ result += $(v:G) ;
+ }
+ }
+ }
+
+ # Strip away last dot separated part and recurse.
+ local next = [ MATCH ^(.+)\\.([^\\.])* : $(rule-or-module) ] ;
+ if $(next)
+ {
+ result += [ relevant-features $(next[1]) ] ;
+ }
+ result = [ sequence.unique $(result) ] ;
+ if $(result[1]) = ""
+ {
+ result = $(result) ;
+ }
+ .relevant-features.$(rule-or-module) = $(result) ;
+ return $(result) ;
+ }
+ else
+ {
+ return $(.relevant-features.$(rule-or-module)) ;
+ }
+}
+
+rule filter-property-set ( rule-or-module : property-set )
+{
+ if ! $(.filtered.property-set.$(rule-or-module).$(property-set))
+ {
+ local relevant = [ relevant-features $(rule-or-module) ] ;
+ local result ;
+ for local p in [ $(property-set).raw ]
+ {
+ if $(p:G) in $(relevant)
+ {
+ result += $(p) ;
+ }
+ }
+ .filtered.property-set.$(rule-or-module).$(property-set) = [ property-set.create $(result) ] ;
+ }
+ return $(.filtered.property-set.$(rule-or-module).$(property-set)) ;
+}
rule set-target-variables ( rule-or-module targets + : property-set )
{
- properties = [ $(property-set).raw ] ;
+ property-set = [ filter-property-set $(rule-or-module) : $(property-set) ] ;
local key = $(rule-or-module).$(property-set) ;
local settings = $(.stv.$(key)) ;
if ! $(settings)
diff --git a/tools/build/v2/build/toolset.py b/tools/build/v2/build/toolset.py
index b426798784..3665ab872e 100644
--- a/tools/build/v2/build/toolset.py
+++ b/tools/build/v2/build/toolset.py
@@ -68,7 +68,9 @@ def reset ():
reset ()
# FIXME: --ignore-toolset-requirements
-# FIXME: using
+def using(toolset_module, *args):
+ loaded_toolset_module= get_manager().projects().load_module(toolset_module, [os.getcwd()]);
+ loaded_toolset_module.init(*args)
# FIXME push-checking-for-flags-module ....
# FIXME: investigate existing uses of 'hack-hack' parameter
@@ -115,8 +117,8 @@ def flags(rule_or_module, variable_name, condition, values = []):
is specified, then the value of 'feature'
will be added.
"""
- caller = bjam.caller()[:-1]
- if not '.' in rule_or_module and caller.startswith("Jamfile"):
+ caller = bjam.caller()
+ if not '.' in rule_or_module and caller and caller[:-1].startswith("Jamfile"):
# Unqualified rule name, used inside Jamfile. Most likely used with
# 'make' or 'notfile' rules. This prevents setting flags on the entire
# Jamfile module (this will be considered as rule), but who cares?
@@ -142,7 +144,7 @@ def flags(rule_or_module, variable_name, condition, values = []):
transformed = []
for c in condition:
# FIXME: 'split' might be a too raw tool here.
- pl = [property.create_from_string(s) for s in c.split('/')]
+ pl = [property.create_from_string(s,False,True) for s in c.split('/')]
pl = feature.expand_subfeatures(pl);
transformed.append(property_set.create(pl))
condition = transformed
@@ -378,7 +380,6 @@ def add_requirements(requirements):
#if ! $(.ignore-requirements)
#{
- print "XXXX", requirements
__requirements.extend(requirements)
#}
diff --git a/tools/build/v2/build/type.py b/tools/build/v2/build/type.py
index ddb7ba09d2..e815739f40 100644
--- a/tools/build/v2/build/type.py
+++ b/tools/build/v2/build/type.py
@@ -81,7 +81,7 @@ def register (type, suffixes = [], base_type = None):
__types [type] = entry
if base_type:
- __types [base_type]['derived'].append (type)
+ __types.setdefault(base_type, {}).setdefault('derived', []).append(type)
if len (suffixes) > 0:
# Generated targets of 'type' will use the first of 'suffixes'
diff --git a/tools/build/v2/build/version.jam b/tools/build/v2/build/version.jam
index 7626ddda8d..512c9ee31a 100644
--- a/tools/build/v2/build/version.jam
+++ b/tools/build/v2/build/version.jam
@@ -7,7 +7,7 @@ import errors ;
import numbers ;
major = "2011" ;
-minor = "04" ;
+minor = "12" ;
rule boost-build ( )
{
diff --git a/tools/build/v2/build_system.py b/tools/build/v2/build_system.py
index 55d8b806ca..cc1a61b2fb 100644
--- a/tools/build/v2/build_system.py
+++ b/tools/build/v2/build_system.py
@@ -20,6 +20,7 @@ from b2.util.sequence import unique
import b2.build.build_request
from b2.build.errors import ExceptionWithUserContext
import b2.tools.common
+from b2.build.toolset import using
import b2.build.project as project
import b2.build.virtual_target as virtual_target
@@ -290,6 +291,9 @@ def load_configuration_files():
initialize_config_module('user-config')
if not test_config and not legacy_ignore_config:
+ # Here, user_config has value of None if nothing is explicitly
+ # specified, and value of '' if user explicitly does not want
+ # to load any user config.
user_config = None
for a in sys.argv:
m = re.match("--user-config=(.*)$", a)
@@ -297,30 +301,32 @@ def load_configuration_files():
user_config = m.group(1)
break
- if not user_config:
+ 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 not user_config:
+
+ if user_config is None:
user_config = "user-config.jam"
- if explicitly_requested:
+ if user_config:
+ if explicitly_requested:
- user_config = os.path.abspath(user_config)
+ user_config = os.path.abspath(user_config)
- if debug_config:
- print "notice: Loading explicitly specified user configuration file:"
- print " " + 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)
+ 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:
- load_config('user-config', os.path.basename(user_config), user_path)
-
- elif debug_config:
- print "notice: User configuration file loading explicitly disabled." ;
+ 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
@@ -381,7 +387,10 @@ def process_explicit_toolset_requests():
if debug_config:
print "notice: [cmdline-cfg] toolset '%s' not previously configured; attempting to auto-configure now" % toolset_version
- toolset.using(toolset, version)
+ if version is not None:
+ using(toolset, version)
+ else:
+ using(toolset)
else:
@@ -515,7 +524,7 @@ def main_real():
print "warning: For more configuration options, please consult"
print "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html"
- toolset.using(dt, dtv)
+ using(dt, dtv)
# Parse command line for targets and properties. Note that this requires
# that all project files already be loaded.
diff --git a/tools/build/v2/doc/src/abstract-target.xml b/tools/build/v2/doc/src/abstract-target.xml
new file mode 100644
index 0000000000..dad53380c4
--- /dev/null
+++ b/tools/build/v2/doc/src/abstract-target.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.abstract-target">
+
+ <title>Class abstract-target</title>
+ <indexterm>
+ <primary>abstract-target</primary>
+ </indexterm>
+
+ <para>
+ Base class for all abstract targets.
+ </para>
+
+<programlisting language="jam">
+class abstract-target {
+ rule <link linkend="bbv2.reference.class.abstract-target.__init__">__init__</link> ( name : project )
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.__init__">generate</link> ( property-set )
+}
+</programlisting>
+
+ <para>
+ Classes derived from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>:
+ <itemizedlist>
+ <listitem>
+ <link linkend="bbv2.reference.class.project-target">project-target</link>
+ </listitem>
+ <listitem>
+ <link linkend="bbv2.reference.class.main-target">main-target</link>
+ </listitem>
+ <listitem>
+ <link linkend="bbv2.reference.class.project-target">basic-target</link>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.abstract-target.__init__">
+ <code language="jam">rule __init__ ( name : project )</code>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem>
+ <para>The name of the target in the Jamfile.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>project</literal></term>
+ <listitem>
+ <para>The <link linkend="bbv2.reference.class.project-target">project</link> to which this target belongs.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.name">
+ <indexterm zone="bbv2.reference.class.abstract-target.name">
+ <primary>name</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule name ( )</code>
+ <para>Returns the name of this target.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.project">
+ <indexterm zone="bbv2.reference.class.abstract-target.project">
+ <primary>project</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule project ( )</code>
+ <para>Returns the <link linkend="bbv2.reference.class.project-target">project</link> for this target.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.location">
+ <indexterm zone="bbv2.reference.class.abstract-target.location">
+ <primary>location</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule location ( )</code>
+ <para>Returns the location where the target was declared.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.full-name">
+ <indexterm zone="bbv2.reference.class.abstract-target.full-name">
+ <primary>full-name</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule full-name ( )</code>
+ <para>Returns a user-readable name for this target.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.abstract-target.generate">
+ <indexterm zone="bbv2.reference.class.abstract-target.generate">
+ <primary>generate</primary>
+ <secondary>Abstract Target</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Generates virtual targets for this abstract target using the specified
+ properties, unless a different value of some feature is required by the
+ target. This is an abstract method which must be overriden by derived
+ classes.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ If <code language="jam">property-set</code> is empty, performs the
+ default build of this target, in a way specific to the derived class.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/basic-target.xml b/tools/build/v2/doc/src/basic-target.xml
new file mode 100644
index 0000000000..ae7c2795c2
--- /dev/null
+++ b/tools/build/v2/doc/src/basic-target.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.basic-target">
+
+ <title>Class basic-target</title>
+ <indexterm>
+ <primary>basic-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class basic-target : <link linkend="bbv2.reference.class.abstract-target">abstract-target</link> {
+ rule <link linkend="bbv2.reference.class.basic-target.__init__">__init__</link> ( name : project : sources * : requirements * : default-build * : usage-requirements * )
+ rule <link linkend="bbv2.reference.class.basic-target.generate">generate</link> ( property-set )
+ rule <link linkend="bbv2.reference.class.basic-target.construct">construct</link> ( name : source-targets * : property-set )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+}
+</programlisting>
+
+ <para>
+ Implements the most standard way of constructing main target alternative from
+ sources. Allows sources to be either files or other main targets and handles
+ generation of those dependency targets.
+ <!-- FIXME: Better description of sources. The sources can be either target
+ references or instances of abstract-target. -->
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.basic-target.__init__">
+ <code language="jam">rule __init__ ( name : project : sources * : requirements * : default-build * : usage-requirements * )</code>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem><para>The name of the target</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>project</literal></term>
+ <listitem>
+ <para>
+ The <link linkend="bbv2.reference.class.project-target">project</link>
+ in which the target is declared.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.basic-target.generate">
+ <indexterm zone="bbv2.reference.class.basic-target.generate">
+ <primary>generate</primary>
+ <secondary>Basic Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Overrides
+ <link linkend="bbv2.reference.class.abstract-target.generate">abstract-target.generate</link>.
+
+ Determines final build properties, generates sources, and calls
+ <link linkend="bbv2.reference.class.basic-target.construct">construct</link>.
+ This method should not be overridden.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.basic-target.construct">
+ <indexterm zone="bbv2.reference.class.basic-target.construct">
+ <primary>construct</primary>
+ <secondary>Basic Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule construct ( name : source-targets * : property-set )</code>
+ <para>
+ Constructs virtual targets for this abstract target. Returns a
+ usage-requirements property-set and a list of virtual
+ targets. Should be overriden in derived classes.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/catalog.xml b/tools/build/v2/doc/src/catalog.xml
deleted file mode 100644
index 26e16145d3..0000000000
--- a/tools/build/v2/doc/src/catalog.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?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:///home/ccurrie/src/boost/tools/boostbook/dtd//"/>
- <rewriteURI uriStartString="http://docbook.sourceforge.net/release/xsl/current/" rewritePrefix="file:///shared/ccurrie/share/sgml/docbook/docbook-xsl-1.64.1/"/>
- <rewriteURI uriStartString="http://www.oasis-open.org/docbook/xml/4.2/" rewritePrefix="file:///shared/ccurrie/share/sgml/docbook/docbook-dtd-4.2/"/>
-</catalog>
diff --git a/tools/build/v2/doc/src/extending.xml b/tools/build/v2/doc/src/extending.xml
index 3d0fda569d..43ef0bbb37 100644
--- a/tools/build/v2/doc/src/extending.xml
+++ b/tools/build/v2/doc/src/extending.xml
@@ -76,17 +76,20 @@
in Jamfile, such as metatarget kind, name, sources and properties,
and can be called with specific properties to generate concrete
targets. At the code level it is represented by an instance of
- class derived from <classname>abstract-target</classname>.
+ class derived from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>.
<footnote><para>This name is historic, and will be eventuall changed to
<code>metatarget</code></para></footnote>
</para>
- <para>The <methodname>generate</methodname> method takes the build properties
- (as an instance of the <classname>property-set</classname> class) and returns
+ <para>The <link linkend="bbv2.reference.class.abstract-target.generate">generate</link>
+ method takes the build properties
+ (as an instance of the <link linkend="bbv2.reference.class.property-set">
+ property-set</link> class) and returns
a list containing:</para>
<itemizedlist>
<listitem><para>As front element&mdash;Usage-requirements from this invocation
- (an instance of <classname>property-set</classname>)</para></listitem>
+ (an instance of <link linkend="bbv2.reference.class.property-set">
+ property-set</link>)</para></listitem>
<listitem><para>As subsequent elements&mdash;created concrete targets (
instances of the <classname>virtual-target</classname> class.)</para></listitem>
</itemizedlist>
@@ -96,47 +99,52 @@
<code>targets.generate-from-reference</code> function can both
lookup and generate a metatarget.</para>
- <para>The <classname>abstract-target</classname> class has three immediate
- derived classes:</para>
+ <para>The <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ class has three immediate derived classes:</para>
<itemizedlist>
- <listitem><para><classname>project-target</classname> that
+ <listitem><para><link linkend="bbv2.reference.class.project-target">project-target</link> that
corresponds to a project and is not intended for further
- subclassing. The <methodname>generate</methodname> method of this
+ subclassing. The <link linkend="bbv2.reference.class.project-target.generate">
+ generate</link> method of this
class builds all targets in the project that are not marked as
explicit.</para></listitem>
- <listitem><para><classname>main-target</classname> corresponds to a target in a project
+ <listitem><para><link linkend="bbv2.reference.class.main-target">main-target</link>
+ corresponds to a target in a project
and contains one or more target alternatives. This class also should not be
- subclassed. The <methodname>generate</methodname> method of this class selects
- an alternative to build, and calls the <methodname>generate</methodname> method of that
- alternative.</para></listitem>
+ subclassed. The <link linkend="bbv2.reference.class.main-target.generate">generate</link>
+ method of this class selects an alternative to build, and calls the
+ <link linkend="bbv2.reference.class.basic-target.generate">generate</link>
+ method of that alternative.</para></listitem>
- <listitem><para><classname>basic-target</classname> corresponds to a
- specific target alternative. This is base class, with a number of
- derived classes. The <methodname>generate</methodname> method
+ <listitem><para><link linkend="bbv2.reference.class.basic-target">basic-target</link>
+ corresponds to a specific target alternative. This is base class,
+ with a number of derived classes. The
+ <link linkend="bbv2.reference.class.basic-target.generate">generate</link> method
processes the target requirements and requested build properties to
determine final properties for the target, builds all sources, and
- finally calls the abstract <classname>construct</classname> method with the list
- of source virtual targets, and the final properties.
+ finally calls the abstract
+ <link linkend="bbv2.reference.class.basic-target.construct">construct</link>
+ method with the list of source virtual targets, and the final properties.
</para></listitem>
</itemizedlist>
- <para>The instances of the <classname>project-target</classname> and
- <classname>main-target</classname> classes are created
+ <para>The instances of the <link linkend="bbv2.reference.class.project-target">project-target</link> and
+ <link linkend="bbv2.reference.class.main-target">main-target</link> classes are created
implicitly&mdash;when loading a new Jamfiles, or when a new target
alternative with as-yet unknown name is created. The instances of the
- classes derived from <classname>basic-target</classname> are typically
- created when Jamfile calls a <firstterm>metatarget rule</firstterm>,
+ classes derived from <link linkend="bbv2.reference.class.basic-target">basic-target</link>
+ are typically created when Jamfile calls a <firstterm>metatarget rule</firstterm>,
such as such as <code>exe</code>.
</para>
<para>It it permissible to create a custom class derived from
- <classname>basic-target</classname> and create new metatarget rule
+ <link linkend="bbv2.reference.class.basic-target">basic-target</link> and create new metatarget rule
that creates instance of such target. However, in the majority
- of cases, a specific subclass of <classname>basic-target</classname>&mdash;
- <classname>typed-target</classname> is used. That class is associated
+ of cases, a specific subclass of <link linkend="bbv2.reference.class.basic-target">basic-target</link>&mdash;
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link> is used. That class is associated
with a <firstterm>type</firstterm> and relays to <firstterm>generators</firstterm>
to construct concrete targets of that type. This process will be explained below.
When a new type is declared, a new metatarget rule is automatically defined.
@@ -153,8 +161,8 @@
subclass is <classname>file-target</classname>. A file target is associated
with an action that creates it&mdash; an instance of the <classname>action</classname>
class. The action, in turn, hold a list of source targets. It also holds the
- <classname>property-set</classname> instance with the build properties that
- should be used for the action.</para>
+ <link linkend="bbv2.reference.class.property-set">property-set</link>
+ instance with the build properties that should be used for the action.</para>
<para>Here's an example of creating a target from another target, <code>source</code></para>
<programlisting>
@@ -200,11 +208,12 @@ return [ sequence.transform virtual-target.register : $(targets) ] ;
fact, Boost.Build defines concept of target type and
<indexterm><primary>generators</primary></indexterm>
<firstterm>generators</firstterm>, and has special metatarget class
- <classname>typed-target</classname>. Target type is merely an
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link>. Target type is merely an
identifier. It is associated with a set of file extensions that
correspond to that type. Generator is an abstraction of a tool. It advertises
the types it produces and, if called with a set of input target, tries to construct
- output targets of the advertised types. Finally, <classname>typed-target</classname>
+ output targets of the advertised types. Finally,
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link>
is associated with specific target type, and relays the generator (or generators)
for that type.
</para>
@@ -393,7 +402,7 @@ import type ;
type.register VERBATIM : verbatim ;
</programlisting>
- <para>The first parameter to <functionname>type.register</functionname> gives
+ <para>The first parameter to <link linkend="bbv2.reference.modules.type.register">type.register</link> gives
the name of the declared type. By convention, it's uppercase. The second
parameter is the suffix for files of this type. So, if Boost.Build sees
<filename>code.verbatim</filename> in a list of sources, it knows that it's of
@@ -1031,8 +1040,8 @@ feature.compose &lt;parallelism&gt;fake : &lt;library&gt;/mpi//fake/&lt;parallel
<section id="bbv2.extending.rules">
<title>Main target rules</title>
<para>
- A main target rule (e.g “<functionname>exe</functionname>”
- Or “<functionname>lib</functionname>”) creates a top-level target. It's quite likely that you'll want to declare your own and
+ A main target rule (e.g “<link linkend="bbv2.tasks.programs">exe</link>”
+ Or “<link linkend="bbv2.tasks.libraries">lib</link>”) creates a top-level target. It's quite likely that you'll want to declare your own and
there are two ways to do that.
<!-- Why did "that" get changed to "this" above? -->
</para>
diff --git a/tools/build/v2/doc/src/faq.xml b/tools/build/v2/doc/src/faq.xml
index 551e22e25b..a648a3761c 100644
--- a/tools/build/v2/doc/src/faq.xml
+++ b/tools/build/v2/doc/src/faq.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" standalone="yes"?>
-<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<chapter id="bbv2.faq">
<title>Frequently Asked Questions</title>
- <section>
+ <section id="bbv2.faq.featurevalue">
<title>
How do I get the current value of feature in Jamfile?
</title>
@@ -13,7 +13,7 @@
<para>
This is not possible, since Jamfile does not have "current" value of any
feature, be it toolset, build variant or anything else. For a single
- invocation of <filename>bjam</filename>, any given main target can be
+ run of Boost.Build, any given main target can be
built with several property sets. For example, user can request two build
variants on the command line. Or one library is built as shared when used
from one application, and as static when used from another. Each Jamfile
@@ -41,7 +41,7 @@
</itemizedlist>
</section>
- <section>
+ <section id="bbv2.faq.duplicate">
<title>
I am getting a "Duplicate name of actual target" error. What does that
mean?
@@ -174,7 +174,7 @@ exe a : a.cpp : &lt;include&gt;$(SOME_LIBRARY_PATH) ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.proporder">
<title>
How to control properties order?
</title>
@@ -203,7 +203,7 @@ exe a : a.cpp : &lt;include&gt;a&amp;&amp;b ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.liborder">
<title>
How to control the library linking order on Unix?
</title>
@@ -257,7 +257,7 @@ local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.projectroot">
<title>
How to get the project root (a.k.a. Jamroot) location?
</title>
@@ -272,7 +272,7 @@ path-constant TOP : . ;
</para>
</section>
- <section>
+ <section id="bbv2.faq.flags">
<title>
How to change compilation flags for one file?
</title>
diff --git a/tools/build/v2/doc/src/howto.xml b/tools/build/v2/doc/src/howto.xml
index bd128a3214..de17a286a8 100644
--- a/tools/build/v2/doc/src/howto.xml
+++ b/tools/build/v2/doc/src/howto.xml
@@ -28,7 +28,7 @@
<para>
If you have questions, please post them to our mailing list (<ulink
url="http://boost.org/more/mailing_lists.htm#jamboost"/>). The mailing list is
- also mirrowed to newsgroup <ulink url="news://news.gmane.org/gmane.comp.lib.boost.build"/>.
+ also mirrored to the newsgroup <ulink url="news://news.gmane.org/gmane.comp.lib.boost.build"/>.
</para>
</chapter>
diff --git a/tools/build/v2/doc/src/install.xml b/tools/build/v2/doc/src/install.xml
index afae46aa15..545f786695 100644
--- a/tools/build/v2/doc/src/install.xml
+++ b/tools/build/v2/doc/src/install.xml
@@ -29,7 +29,7 @@
<listitem>
<simpara>
Run
- <screen>./bjam install --prefix=<replaceable>PREFIX</replaceable></screen>
+ <screen>./b2 install --prefix=<replaceable>PREFIX</replaceable></screen>
where <replaceable>PREFIX</replaceable> is a directory where you
want Boost.Build to be installed.
</simpara>
@@ -43,15 +43,15 @@
</listitem>
</orderedlist>
- <para>If you are not using Boost.Build package, but rather the version
+ <para>If you are not using a Boost.Build package, but rather the version
bundled with the Boost C++ Libraries, the above commands should be run
in the <filename>tools/build/v2</filename> directory.</para>
<para>
- Now that Boost.Build is installed, you can try some of examples. Copy
+ Now that Boost.Build is installed, you can try some of the examples. Copy
<filename><replaceable>PREFIX</replaceable>/share/boost-build/examples/hello</filename>
to a different directory, then change to that directory and run:
-<screen><filename><replaceable>PREFIX</replaceable>/bin/bjam</filename></screen>
+<screen><filename><replaceable>PREFIX</replaceable>/bin/b2</filename></screen>
A simple executable should be built.
</para>
diff --git a/tools/build/v2/doc/src/main-target.xml b/tools/build/v2/doc/src/main-target.xml
new file mode 100644
index 0000000000..84afac14f8
--- /dev/null
+++ b/tools/build/v2/doc/src/main-target.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.main-target">
+
+ <title>Class main-target</title>
+ <indexterm>
+ <primary>main-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class main-target : <link linkend="bbv2.reference.class.abstract-target">abstract-target</link> {
+ rule <link linkend="bbv2.reference.class.main-target.generate">generate</link> ( property-set )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+}
+</programlisting>
+
+ <para>
+ A <link linkend="bbv2.reference.class.main-target">main-target</link>
+ represents a named top-level target in a Jamfile.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.main-target.generate">
+ <indexterm zone="bbv2.reference.class.main-target.generate">
+ <primary>generate</primary>
+ <secondary>Main Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Overrides
+ <link linkend="bbv2.reference.class.abstract-target.generate">abstract-target.generate</link>.
+
+ Select an alternative for this main target, by finding all alternatives
+ whose requirements are satisfied by <literal>property-set</literal> and
+ picking the one with the longest requirements set. Returns the result
+ of calling <link linkend="bbv2.reference.class.basic-target.generate">generate</link>
+ on that alternative.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/overview.xml b/tools/build/v2/doc/src/overview.xml
index 048898867e..90b7c27227 100644
--- a/tools/build/v2/doc/src/overview.xml
+++ b/tools/build/v2/doc/src/overview.xml
@@ -17,20 +17,20 @@
Boost.Build actually consists of two parts - Boost.Jam, a build engine
with its own interpreted language, and Boost.Build itself, implemented in
Boost.Jam's language. The chain of events when you type
- <command>bjam</command> on the command line is as follows:
+ <command>b2</command> on the command line is as follows:
<orderedlist>
<listitem>
<para>
- Boost.Jam tries to find Boost.Build and loads the top-level module.
- The exact process is described in <xref linkend=
+ 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>
</listitem>
<listitem>
<para>
The top-level module loads user-defined configuration files,
- <filename>user-config.jam</filename> and <filename>site-config.jam
- </filename>, which define available toolsets.
+ <filename>user-config.jam</filename> and
+ <filename>site-config.jam</filename>, which define available toolsets.
</para>
</listitem>
<listitem>
@@ -97,8 +97,8 @@
a.o: a.c
g++ -o a.o -g a.c
</programlisting>
- This is rather low-level description mechanism and it's hard to adjust commands, options,
- and sets of created targets depending on the used compiler and operating system.
+ 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.
</para>
<para>
@@ -107,20 +107,20 @@ a.o: a.c
<programlisting>
add_program ("a", "a.c")
</programlisting>
- This is a function call that creates targets necessary to create executable file
- from source file <filename>a.c</filename>. Depending on configured properties,
- different commands line may be used. However, <code>add_program</code> is higher-level,
- but rather thin level. All targets are created immediately when build description
+ This is a function call that creates the targets necessary to create a executable file
+ from the source file <filename>a.c</filename>. Depending on configured properties,
+ 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 complete reconfiguration of the build tree.
+ in any build property requires a complete reconfiguration of the build tree.
</para>
<para>
- In order to support true multivariant builds, Boost.Build introduces the concept of
+ In order to support true multivariant builds, Boost.Build introduces the concept of a
<indexterm> <primary>metatarget</primary> <secondary>definition</secondary></indexterm>
<indexterm> <primary>main target</primary> <see>metataget</see> </indexterm>
- <firstterm>metatarget</firstterm>&mdash;object that is created when build description
- is parsed and can be later called with specific build properties to generate
+ <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.
</para>
@@ -130,11 +130,11 @@ add_program ("a", "a.c")
exe a : a.cpp ;
</programlisting>
When this declaration is parsed, Boost.Build creates a metatarget, but does not
- yet decides what files must be created, or what commands must be used. After
- all build files are parsed, Boost.Build considers properties requested on the
+ yet decide what files must be created, or what commands must be used. After
+ all build files are parsed, Boost.Build considers the properties requested on the
command line. Supposed you have invoked Boost.Build with:
<screen>
-bjam toolset=gcc toolset=msvc
+b2 toolset=gcc toolset=msvc
</screen>
In that case, the metatarget will be called twice, once with <code>toolset=gcc</code>
and once with <code>toolset=msvc</code>. Both invocations will produce concrete
@@ -142,9 +142,9 @@ bjam toolset=gcc toolset=msvc
</para>
<para>
- Another key concept is
+ Another key concept is
<indexterm><primary>property</primary><secondary>definition</secondary></indexterm>
- <firstterm>build property</firstterm>. Build property is a variable
+ <firstterm>build property</firstterm>. A build property is a variable
that affects the build process. It can be specified on the command line, and is
passed when calling a metatarget. While all build tools have a similar mechanism,
Boost.Build differs by requiring that all build properties are declared in advance,
@@ -158,12 +158,12 @@ bjam toolset=gcc toolset=msvc
"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"/>).
- Then, the dependency metatargets are called with modified properties and produce
- concrete targets that are then used in build process. Of course, dependency metatargets
+ Then, the dependency metatargets are called with the modified properties and produce
+ concrete targets that are then used in the build process. Of course, dependency metatargets
maybe in turn modify build properties and have dependencies of their own.
</para>
- <para>For 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>
@@ -173,8 +173,8 @@ bjam toolset=gcc toolset=msvc
<title>Boost.Jam Language</title>
<para>
- This section will describe the basics of the Boost.Jam language&#x2014;
- just enough for writing Jamfiles. For more information, please see the
+ This section will describe the basics of the Boost.Jam language&#x2014;just
+ enough for writing Jamfiles. For more information, please see the
<link linkend="bbv2.jam">Boost.Jam</link> documentation.
</para>
@@ -182,8 +182,8 @@ bjam toolset=gcc toolset=msvc
<link linkend="bbv2.jam">Boost.Jam</link> has an interpreted, procedural
language. On the lowest level, a <link linkend="bbv2.jam">Boost.Jam
</link> program consists of variables and <indexterm><primary>rule
- </primary></indexterm> <firstterm>rules</firstterm> (Jam term for
- function). They are grouped into modules&#x2014;there is one global
+ </primary></indexterm> <firstterm>rules</firstterm> (the Jam term for
+ functions). They are grouped into modules&#x2014;there is one global
module and a number of named modules. Besides that, a <link linkend=
"bbv2.jam">Boost.Jam</link> program contains classes and class
instances.
@@ -325,7 +325,7 @@ rule test ( )
import <replaceable>module</replaceable> ;
import <replaceable>module</replaceable> : <replaceable>rule</replaceable> ;
</programlisting>
- The first form imports the specified bjam module. All rules from that
+ The first form imports the specified module. All rules from that
module are made available using the qualified name: <code><replaceable>
module</replaceable>.<replaceable>rule</replaceable></code>. The second
form imports the specified rules only, and they can be called using
@@ -333,8 +333,8 @@ import <replaceable>module</replaceable> : <replaceable>rule</replaceable> ;
</para>
<para id="bbv2.overview.jam_language.actions">
- Sometimes, you'd need to specify the actual command lines to be used
- when creating targets. In jam language, you use named actions to do
+ Sometimes, you need to specify the actual command lines to be used
+ when creating targets. In the jam language, you use named actions to do
this. For example:
<programlisting>
actions create-file-from-another
@@ -350,8 +350,8 @@ actions create-file-from-another
</para>
<para>
- To flexibly adjust the command line, you can define a rule with the same
- name as the action and taking three parameters -- targets, sources and
+ To adjust the command line flexibly, you can define a rule with the same
+ name as the action and taking three parameters&mdash;targets, sources and
properties. For example:
<programlisting>
rule create-file-from-another ( targets * : sources * : properties * )
@@ -366,8 +366,8 @@ actions create-file-from-another
create-file-from-another $(OPTIONS) $(&lt;) $(&gt;)
}
</programlisting>
- In this example, the rule checks if certain build property is specified.
- If so, it sets variable <varname>OPIONS</varname> that is then used
+ 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
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
@@ -375,7 +375,7 @@ actions create-file-from-another
</para>
<para>
- More details can be found in Jam reference, <xref
+ More details can be found in the Jam reference, <xref
linkend="jam.language.rules"/>.
</para>
</section>
@@ -386,9 +386,9 @@ actions create-file-from-another
<para>
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 system administrator, and
- the second is for user to modify. You can edit the one in the top-level
- directory of Boost.Build installation or create a copy in your home
+ 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
+ directory of your Boost.Build installation or create a copy in your home
directory and edit the copy. The following table explains where both files
are searched.
</para>
@@ -453,7 +453,7 @@ actions create-file-from-another
</tip>
<para>
- Usually, <filename>user-config.jam</filename> just defines available compilers
+ Usually, <filename>user-config.jam</filename> just defines the available compilers
and other tools (see <xref linkend="bbv2.recipies.site-config"/> for more advanced
usage). A tool is configured using the following syntax:
</para>
@@ -462,7 +462,7 @@ actions create-file-from-another
using <replaceable>tool-name</replaceable> : ... ;
</programlisting>
<para>
- The <functionname>using</functionname> rule is given a name of tool, and
+ The <code language="jam">using</code> rule is given the name of tool, and
will make that tool available to Boost.Build. For example,
<programlisting>
using gcc ;
@@ -476,9 +476,9 @@ using gcc ;
</para>
<para>
- For all the C++ compiler toolsets Boost.Build supports
+ For all the C++ compiler toolsets that Boost.Build supports
out-of-the-box, the list of parameters to
- <functionname>using</functionname> is the same: <parameter
+ <code language="jam">using</code> is the same: <parameter
class="function">toolset-name</parameter>, <parameter
class="function">version</parameter>, <parameter
class="function">invocation-command</parameter>, and <parameter
@@ -509,8 +509,8 @@ using msvc : : "Z:/Programs/Microsoft Visual Studio/vc98/bin/cl" ;
<para>
Some Boost.Build toolsets will use that path to take additional actions
required before invoking the compiler, such as calling vendor-supplied
- scripts to set up its required environment variables. When compiler
- executables for C and C++ are different, path to the C++ compiler
+ scripts to set up its required environment variables. When the compiler
+ executables for C and C++ are different, the path to the C++ compiler
executable must be specified. The command can
be any command allowed by the operating system. For example:
<programlisting>
@@ -521,13 +521,13 @@ using msvc : : echo Compiling &#x26;&#x26; foo/bar/baz/cl ;
<para>
To configure several versions of a toolset, simply invoke the
- <functionname>using</functionname> rule multiple times:
+ <code language="jam">using</code> rule multiple times:
<programlisting>
using gcc : 3.3 ;
using gcc : 3.4 : g++-3.4 ;
using gcc : 3.2 : g++-3.2 ;
</programlisting>
- Note that in the first call to <functionname>using</functionname>, the
+ Note that in the first call to <code language="jam">using</code>, the
compiler found in the <envar>PATH</envar> will be used, and there is no
need to explicitly specify the command.
</para>
@@ -581,13 +581,13 @@ using gcc : 3.4 : g++-3.4 ;
<section id="bbv2.overview.invocation">
<title>Invocation</title>
- <para>To invoke Boost.Build, type <command>bjam</command> on the command line. Three kinds
+ <para>To invoke Boost.Build, type <command>b2</command> on the command line. Three kinds
of command-line tokens are accepted, in any order:</para>
<variablelist>
<varlistentry>
<term>options</term>
- <listitem><para>Options start with either dash, or two dashes. The standard options
+ <listitem><para>Options start with either one or two dashes. The standard options
are listed below, and each project may add additional options</para></listitem>
</varlistentry>
@@ -595,8 +595,8 @@ using gcc : 3.4 : g++-3.4 ;
<term>properties</term>
<listitem><para>Properties specify details of what you want to build (e.g. debug
- or release variant). Syntactically, all command line tokens with equal sign in them
- are considered to specify properties. In the simplest form, property looks like
+ or release variant). Syntactically, all command line tokens with an equal sign in them
+ are considered to specify properties. In the simplest form, a property looks like
<command><replaceable>feature</replaceable>=<replaceable>value</replaceable></command>
</para></listitem>
</varlistentry>
@@ -613,22 +613,22 @@ using gcc : 3.4 : g++-3.4 ;
<section id="bbv2.overview.invocation.examples">
<title>Examples</title>
- <para>To build all targets defined in Jamfile in the current directory with default properties, run:
+ <para>To build all targets defined in the Jamfile in the current directory with the default properties, run:
<screen>
-bjam
+b2
</screen>
</para>
<para>To build specific targets, specify them on the command line:
<screen>
-bjam lib1 subproject//lib2
+b2 lib1 subproject//lib2
</screen>
</para>
<para>To request a certain value for some property, add <literal>
<replaceable>property</replaceable>=<replaceable>value</replaceable></literal> to the command line:
<screen>
-bjam toolset=gcc variant=debug optimization=space
+b2 toolset=gcc variant=debug optimization=space
</screen>
</para>
</section>
@@ -673,8 +673,8 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--build-dir</option></term>
<listitem>
- <para>Changes build directories for all project roots being built. When
- this option is specified, all Jamroot files should declare project name.
+ <para>Changes the build directories for all project roots being built. When
+ this option is specified, all Jamroot files must declare a project name.
The build directory for the project root will be computed by concatanating
the value of the <option>--build-dir</option> option, the project name
specified in Jamroot, and the build dir specified in Jamroot
@@ -690,7 +690,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--version</option></term>
<listitem>
- <para>Prints information on Boost.Build and Boost.Jam
+ <para>Prints information on the Boost.Build and Boost.Jam
versions.
</para>
</listitem>
@@ -713,7 +713,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>-q</option></term>
<listitem>
- <para>Stop at first error, as opposed to continuing to build targets
+ <para>Stop at the first error, as opposed to continuing to build targets
that don't depend on the failed ones.</para>
</listitem>
</varlistentry>
@@ -728,7 +728,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--debug-configuration</option></term>
<listitem>
- <para>Produces debug information about loading of Boost.Build
+ <para>Produces debug information about the loading of Boost.Build
and toolset files.</para>
</listitem>
</varlistentry>
@@ -744,7 +744,7 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--debug-generators</option></term>
<listitem>
- <para>Produces debug output from generator search process.
+ <para>Produces debug output from the generator search process.
Useful for debugging custom generators.
</para>
</listitem>
@@ -753,8 +753,8 @@ bjam toolset=gcc variant=debug optimization=space
<varlistentry>
<term><option>--ignore-config</option></term>
<listitem>
- <para>Do not load <literal>site-config.jam</literal> and
- <literal>user-config.jam</literal> configuration files.
+ <para>Do not load <literal>site-config.jam</literal> or
+ <literal>user-config.jam</literal>.
</para>
</listitem>
</varlistentry>
@@ -937,11 +937,12 @@ bjam toolset=gcc variant=debug optimization=space
</tgroup>
</table>
- If you have more than one version of a given C++ toolset (e.g. configured in
+ <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
<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>
@@ -951,21 +952,21 @@ bjam toolset=gcc variant=debug optimization=space
once for each specified value of a feature. For example, if you use
</para>
<screen>
-bjam link=static link=shared threading=single threading=multi
+b2 link=static link=shared threading=single threading=multi
</screen>
<para>
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 commands, for example:
+ you can separate the values with commas, for example:
</para>
<screen>
-bjam link=static,shared threading=single,multi
+b2 link=static,shared threading=single,multi
</screen>
<para>
- The comma has special meaning only if the feature has a fixed set of values, so
+ The comma has this special meaning only if the feature has a fixed set of values, so
</para>
<screen>
-bjam include=static,shared
+b2 include=static,shared
</screen>
<para>is not treated specially.</para>
@@ -1068,7 +1069,7 @@ rule <replaceable>rule-name</replaceable> (
</para>
<para>The actual requirements for a target are obtained by refining
- requirements of the project where a target is declared with the
+ the requirements of the project where the target is declared with the
explicitly specified requirements. The same is true for
usage-requirements. More details can be found in
<xref linkend="bbv2.reference.variants.proprefine"/>
@@ -1108,7 +1109,8 @@ obj test.debug : test.cpp : &lt;variant&gt;debug ;
files. Sometimes, you'll want to automatically construct the
list of source files rather than having to spell it out
manually, in which case you can use the
- <functionname>glob</functionname> rule. Here are two examples:</para>
+ <link linkend="bbv2.reference.rules.glob">glob</link> rule.
+ Here are two examples:</para>
<programlisting>
exe a : a.cpp ; # a.cpp is the only source file
exe b : [ glob *.cpp ] ; # all .cpp files in this directory are sources
@@ -1158,7 +1160,7 @@ exe c : c.cpp /boost/program_options//program_options ;
<programlisting>
exe hello : hello.cpp : &lt;include&gt;/opt/boost &lt;define&gt;MY_DEBUG ;
</programlisting>
- There is a number of other features, listed in
+ There are a number of other features, listed in
<xref linkend="bbv2.overview.builtins.features"/>. For example if
a library can only be built statically, or a file can't be compiled
with optimization due to a compiler bug, one can use
@@ -1221,13 +1223,13 @@ rule my-rule ( properties * )
<para>Requirements explicitly specified for a target are usually
combined with the requirements specified for the containing project. You
- can cause a target to completely ignore specific project's requirement
- using the syntax by adding a minus sign before a property, for example:
+ can cause a target to completely ignore a specific project requirement
+ using the syntax by adding a minus sign before the property, for example:
<programlisting>
exe main : main.cpp : <emphasis role="bold">-&lt;define&gt;UNNECESSARY_DEFINE</emphasis> ;
</programlisting>
- This syntax is the only way to ignore free properties from a parent,
- such as defines. It can be also useful for ordinary properties. Consider
+ This syntax is the only way to ignore free properties, such as defines,
+ from a parent. It can be also useful for ordinary properties. Consider
this example:
<programlisting>
project test : requirements &lt;threading&gt;multi ;
@@ -1235,12 +1237,12 @@ exe test1 : test1.cpp ;
exe test2 : test2.cpp : &lt;threading&gt;single ;
exe test3 : test3.cpp : -&lt;threading&gt;multi ;
</programlisting>
- Here, <code>test1</code> inherits project requirements and will always
+ Here, <code>test1</code> inherits the project requirements and will always
be built in multi-threaded mode. The <code>test2</code> target
- <emphasis>overrides</emphasis> project's requirements and will
+ <emphasis>overrides</emphasis> the project's requirements and will
always be built in single-threaded mode. In contrast, the
<code>test3</code> target <emphasis>removes</emphasis> a property
- from project requirements and will be built either in single-threaded or
+ from the project requirements and will be built either in single-threaded or
multi-threaded mode depending on which variant is requested by the
user.</para>
@@ -1260,7 +1262,7 @@ exe hello : hello.cpp : : &lt;threading&gt;multi ;
</programlisting>
would build a multi-threaded target unless the user
explicitly requests a single-threaded version. The difference between
- requirements and default-build is that requirements cannot be
+ the requirements and the default-build is that the requirements cannot be
overridden in any way.
</para>
</section>
@@ -1276,7 +1278,7 @@ exe hello : hello.cpp : : &lt;threading&gt;multi ;
it. We can express this situation using <firstterm>target
alternatives</firstterm>:
<programlisting>
-lib demangler : dummy_demangler.cpp ; # alternative 1
+lib demangler : dummy_demangler.cpp ; # alternative 1
lib demangler : demangler_gcc.cpp : &lt;toolset&gt;gcc ; # alternative 2
lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3
</programlisting>
@@ -1299,13 +1301,13 @@ exe hello : hello.cpp
optimization. When referring to an inline main target, its declared
name must be prefixed by its parent target's name and two dots. In
the example above, to build only helpers, one should run
- <code>bjam hello..helpers</code>.
+ <code>b2 hello..helpers</code>.
</para>
<para>When no target is requested on the command line, all targets in the
current project will be built. If a target should be built only by
explicit request, this can be expressed by the
- <functionname>explicit</functionname> rule:
+ <link linkend="bbv2.reference.rules.explicit">explicit</link> rule:
<programlisting>
explicit install_programs ;</programlisting>
</para>
@@ -1325,7 +1327,7 @@ explicit install_programs ;</programlisting>
</para>
<para>Projects are named using the
- <functionname>project</functionname> rule, which has the
+ <code language="jam">project</code> rule, which has the
following syntax:
<programlisting>
project <replaceable>id</replaceable> : <replaceable>attributes</replaceable> ;
@@ -1388,7 +1390,7 @@ project tennis
<entry>Default value</entry>
- <entry>Handling by the <functionname>project</functionname>
+ <entry>Handling by the <code language="jam">project</code>
rule</entry>
</row>
@@ -1541,7 +1543,7 @@ project tennis
The command line specifies which targets to build and with which
properties. For example:
<programlisting>
-bjam app1 lib1//lib1 toolset=gcc variant=debug optimization=full
+b2 app1 lib1//lib1 toolset=gcc variant=debug optimization=full
</programlisting>
would build two targets, "app1" and "lib1//lib1" with the specified
properties. You can refer to any targets, using
@@ -1549,7 +1551,7 @@ bjam app1 lib1//lib1 toolset=gcc variant=debug optimization=full
properties. Some of the properties are very common, and for them the name
of the property can be omitted. For example, the above can be written as:
<programlisting>
-bjam app1 lib1//lib1 gcc debug optimization=full
+b2 app1 lib1//lib1 gcc debug optimization=full
</programlisting>
The complete syntax, which has some additional shortcuts, is
described in <xref linkend="bbv2.overview.invocation"/>.
@@ -1640,7 +1642,7 @@ bjam app1 lib1//lib1 gcc debug optimization=full
<section><title>Building a Project</title>
<para>Often, a user builds a complete project, not just one main
- target. In fact, invoking <command>bjam</command> without
+ target. In fact, invoking <command>b2</command> without
arguments
<!-- do you know the difference between parameters and
arguments? I only learned this year -->
diff --git a/tools/build/v2/doc/src/path.xml b/tools/build/v2/doc/src/path.xml
new file mode 100644
index 0000000000..31f47a8dca
--- /dev/null
+++ b/tools/build/v2/doc/src/path.xml
@@ -0,0 +1,248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.modules.path">
+
+ <title>path</title>
+ <indexterm>
+ <primary>path</primary>
+ </indexterm>
+
+ <para>
+ Performs various path manipulations. Paths are always in a 'normalized'
+ representation. In it, a path may be either:
+
+ <itemizedlist>
+ <listitem><para><code>'.'</code>, or</para></listitem>
+ <listitem>
+ <para>
+ <code>['/'] [ ( '..' '/' )* (token '/')* token ]</code>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ In plain english, a path can be rooted, <code>'..'</code>
+ elements are allowed only at the beginning, and it never
+ ends in slash, except for the path consisting of slash only.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.modules.path.make">
+ <indexterm zone="bbv2.reference.modules.path.make">
+ <primary>make</primary>
+ <secondary>path</secondary>
+ </indexterm>
+ <code language="jam">rule make ( native )</code>
+ <para>Converts the native path into normalized form.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.native">
+ <indexterm zone="bbv2.reference.modules.path.native">
+ <primary>native</primary>
+ </indexterm>
+ <code language="jam">rule native ( path )</code>
+ <para>Builds the native representation of the path.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.is-rooted">
+ <indexterm zone="bbv2.reference.modules.path.is-rooted">
+ <primary>is-rooted</primary>
+ </indexterm>
+ <code language="jam">rule is-rooted ( path )</code>
+ <para>Tests if a path is rooted.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.has-parent">
+ <indexterm zone="bbv2.reference.modules.path.has-parent">
+ <primary>has-parent</primary>
+ </indexterm>
+ <code language="jam">rule has-parent ( path )</code>
+ <para>Tests if a path has a parent.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.basename">
+ <indexterm zone="bbv2.reference.modules.path.basename">
+ <primary>basename</primary>
+ </indexterm>
+ <code language="jam">rule basename ( path )</code>
+ <para>Returns the path without any directory components.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.parent">
+ <indexterm zone="bbv2.reference.modules.path.parent">
+ <primary>parent</primary>
+ </indexterm>
+ <code language="jam">rule parent ( path )</code>
+ <para>Returns the parent directory of the path. If no parent exists, an error is issued.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.reverse">
+ <indexterm zone="bbv2.reference.modules.path.reverse">
+ <primary>reverse</primary>
+ </indexterm>
+ <code language="jam">rule reverse ( path )</code>
+ <para>
+ Returns <code language="jam">path2</code> such that
+ <code language="jam">[ join path path2 ] = "."</code>.
+ The path may not contain <code language="jam">".."</code>
+ element or be rooted.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.join">
+ <indexterm zone="bbv2.reference.modules.path.join">
+ <primary>join</primary>
+ </indexterm>
+ <code language="jam">rule join ( elements + )</code>
+ <para>
+ Concatenates the passed path elements. Generates an error if any
+ element other than the first one is rooted. Skips any empty or
+ undefined path elements.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.root">
+ <indexterm zone="bbv2.reference.modules.path.root">
+ <primary>root</primary>
+ </indexterm>
+ <code language="jam">rule root ( path root )</code>
+ <para>
+ If <code language="jam">path</code> is relative, it is rooted at
+ <code language="jam">root</code>. Otherwise, it is unchanged.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.pwd">
+ <indexterm zone="bbv2.reference.modules.path.pwd">
+ <primary>pwd</primary>
+ </indexterm>
+ <code language="jam">rule pwd ( )</code>
+ <para>Returns the current working directory.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.glob">
+ <indexterm zone="bbv2.reference.modules.path.glob">
+ <primary>glob</primary>
+ </indexterm>
+ <code language="jam">rule glob ( dirs * : patterns + : exclude-patterns * )</code>
+ <para>
+ Returns the list of files matching the given pattern in the specified
+ directory. Both directories and patterns are supplied as portable paths. Each
+ pattern should be a non-absolute path, and can't contain "." or ".." elements.
+ Each slash separated element of a pattern can contain the following special
+ characters:
+ <itemizedlist>
+ <listitem>
+ <para>'?' matches any character</para>
+ </listitem>
+ <listitem>
+ <para>'*' matches an arbitrary number of characters</para>
+ </listitem>
+ </itemizedlist>
+ A file $(d)/e1/e2/e3 (where 'd' is in $(dirs)) matches the pattern p1/p2/p3 if and
+ only if e1 matches p1, e2 matches p2 and so on.
+
+ For example:
+<programlisting language="jam">
+[ glob . : *.cpp ]
+[ glob . : */build/Jamfile ]
+</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.glob-tree">
+ <indexterm zone="bbv2.reference.modules.path.glob-tree">
+ <primary>glob-tree</primary>
+ </indexterm>
+ <code language="jam">rule glob-tree ( roots * : patterns + : exclude-patterns * )</code>
+ <para>
+ Recursive version of <link linkend="bbv2.reference.modules.path.glob">glob</link>.
+ Builds the glob of files while also searching in
+ the subdirectories of the given roots. An optional set of exclusion patterns
+ will filter out the matching entries from the result. The exclusions also
+ apply to the subdirectory scanning, such that directories that match the
+ exclusion patterns will not be searched.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.exists">
+ <indexterm zone="bbv2.reference.modules.path.exists">
+ <primary>exists</primary>
+ </indexterm>
+ <code language="jam">rule exists ( file )</code>
+ <para>Returns true if the specified file exists.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.all-parents">
+ <indexterm zone="bbv2.reference.modules.path.all-parents">
+ <primary>all-parents</primary>
+ </indexterm>
+ <code language="jam">rule all-parents ( path : upper_limit ? : cwd ? )</code>
+ <para>
+ Find out the absolute name of path and return the list of all the parents,
+ starting with the immediate one. Parents are returned as relative names. If
+ <code language="jam">upper_limit</code> is specified, directories above it
+ will be pruned.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.glob-in-parents">
+ <indexterm zone="bbv2.reference.modules.path.glob-in-parents">
+ <primary>glob-in-parents</primary>
+ </indexterm>
+ <code language="jam">rule glob-in-parents ( dir : patterns + : upper-limit ? )</code>
+ <para>
+ Search for <code language="jam">patterns</code> in parent directories
+ of <code language="jam">dir</code>, up to and including
+ <code language="jam">upper_limit</code>, if it is specified, or
+ till the filesystem root otherwise.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.relative">
+ <indexterm zone="bbv2.reference.modules.path.relative">
+ <primary>relative</primary>
+ </indexterm>
+ <code language="jam">rule relative ( child parent : no-error ? )</code>
+ <para>
+ Assuming <code language="jam">child</code> is a subdirectory of
+ <code language="jam">parent</code>, return the relative path from
+ <code language="jam">parent</code> to <code language="jam">child</code>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.relative-to">
+ <indexterm zone="bbv2.reference.modules.path.relative-to">
+ <primary>relative-to</primary>
+ </indexterm>
+ <code language="jam">rule relative-to ( path1 path2 )</code>
+ <para>Returns the minimal path to path2 that is relative path1.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.programs-path">
+ <indexterm zone="bbv2.reference.modules.path.programs-path">
+ <primary>programs-path</primary>
+ </indexterm>
+ <code language="jam">rule programs-path ( )</code>
+ <para>
+ Returns the list of paths which are used by the operating system for
+ looking up programs.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.path.mkdirs">
+ <indexterm zone="bbv2.reference.modules.path.mkdirs">
+ <primary>mkdirs</primary>
+ </indexterm>
+ <code language="jam">rule makedirs ( path )</code>
+ <para>
+ Creates a directory and all parent directories that do not
+ already exist.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/project-target.xml b/tools/build/v2/doc/src/project-target.xml
new file mode 100644
index 0000000000..1e4e39a520
--- /dev/null
+++ b/tools/build/v2/doc/src/project-target.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.project-target">
+
+ <title>Class project-target</title>
+ <indexterm>
+ <primary>project-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class project-target : <link linkend="bbv2.reference.class.abstract-target">abstract-target</link> {
+ rule <link linkend="bbv2.reference.class.project-target.generate">generate</link> ( property-set )
+ rule <link linkend="bbv2.reference.class.project-target.build-dir">build-dir</link> ( )
+ rule <link linkend="bbv2.reference.class.project-target.main-target">main-target</link> ( name )
+ rule <link linkend="bbv2.reference.class.project-target.has-main-target">has-main-target</link> ( name )
+ rule <link linkend="bbv2.reference.class.project-target.find">find</link> ( id : no-error ? )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+}
+</programlisting>
+
+ <para>
+ This class has the following responsibilities:
+ <itemizedlist>
+ <listitem>
+ <para>
+ Maintaining a list of main targets in this project and building them.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.project-target.generate">
+ <indexterm zone="bbv2.reference.class.project-target.generate">
+ <primary>generate</primary>
+ <secondary>Project Target</secondary>
+ </indexterm>
+ <code language="jam">rule generate ( property-set )</code>
+ <para>
+ Overrides
+ <link linkend="bbv2.reference.class.abstract-target.generate">abstract-target.generate</link>.
+
+ Generates virtual targets for all the targets contained in this project.
+ </para>
+
+ <para>
+ On success, returns:
+ <itemizedlist>
+ <listitem>a property-set with the usage requirements to be applied to dependents</listitem>
+ <listitem>a list of produced virtual targets, which may be empty.</listitem>
+ </itemizedlist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.build-dir">
+ <indexterm zone="bbv2.reference.class.project-target.build-dir">
+ <primary>build-dir</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule build-dir ( )</code>
+ <para>
+ Returns the root build directory of the project.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.main-target">
+ <indexterm zone="bbv2.reference.class.project-target.main-target">
+ <primary>main-target</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule main-target ( name )</code>
+ <para>
+ Returns a <link linkend="bbv2.reference.class.main-target">main-target</link>
+ class instance corresponding to <literal>name</literal>.
+ Can only be called after the project has been fully loaded.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.has-main-target">
+ <indexterm zone="bbv2.reference.class.project-target.has-main-target">
+ <primary>has-main-target</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule has-main-target ( name )</code>
+ <para>
+ Returns whether a <link linkend="bbv2.reference.class.main-target">main-target</link>
+ with the specified name exists.
+ Can only be called after the project has been fully loaded.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.project-target.find">
+ <indexterm zone="bbv2.reference.class.project-target.find">
+ <primary>find</primary>
+ <secondary>Project Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule find ( id : no-error ? )</code>
+ <para>
+ Find and return the target with the specified id, treated relative to
+ self. Id may specify either a target or a file name with the target taking
+ priority. May report an error or return nothing if the target is not found
+ depending on the <literal>no-error</literal> parameter.
+ </para>
+ </listitem>
+
+ <!--
+
+ I'm not sure whether these should be considered public interfaces.
+ Leave them out for now (SW):
+
+ rule project-module ( )
+ rule get ( attribute )
+
+ -->
+
+ <!--
+
+ The following are not documented because I consider them implementation details (SW):
+
+ rule __init__ ( name : project-module parent-project ?
+ : requirements * : default-build * ) - invoked by the build system.
+
+ rule targets-to-build ( ) - internal to project-target
+ rule mark-target-as-explicit ( target-name * ) - Implementation of explicit
+ rule mark-target-as-always ( target-name * ) - Implementation of always
+ rule add-alternative ( target-instance ) - Implementation of targets.main-target-alternative
+ rule find-really ( id ) - internal to project-target
+ rule build-main-targets ( ) - internal to project-target
+ rule inherit ( parent ) - internal to project-target
+ rule add-constant ( name : value + : type ? ) - Implementation of constant/path-constant
+
+ -->
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/property-set.xml b/tools/build/v2/doc/src/property-set.xml
new file mode 100644
index 0000000000..a5b5b8c7f6
--- /dev/null
+++ b/tools/build/v2/doc/src/property-set.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.property-set">
+
+ <title>Class property-set</title>
+ <indexterm>
+ <primary>property-set</primary>
+ </indexterm>
+
+ <para>Class for storing a set of properties.</para>
+
+<programlisting language="jam">
+class property-set {
+ rule <link linkend="bbv2.reference.class.property-set.raw">raw</link> ( )
+ rule <link linkend="bbv2.reference.class.property-set.str">str</link> ( )
+ rule <link linkend="bbv2.reference.class.property-set.propagated">propagated</link> ( )
+ rule <link linkend="bbv2.reference.class.property-set.add">add</link> ( ps )
+ rule <link linkend="bbv2.reference.class.property-set.add-raw">add-raw</link> ( properties * )
+ rule <link linkend="bbv2.reference.class.property-set.refine">refine</link> ( ps )
+ rule <link linkend="bbv2.reference.class.property-set.get">get</link> ( feature )
+}
+</programlisting>
+
+ <para>
+ There is 1&lt;-&gt;1 correspondence between identity and value. No two instances
+ of the class are equal. To maintain this property, the 'property-set.create'
+ rule should be used to create new instances. Instances are immutable.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.property-set.raw">
+ <indexterm zone="bbv2.reference.class.property-set.raw">
+ <primary>raw</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule raw ( )</code>
+ <para>Returns a Jam list of the stored properties.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.str">
+ <indexterm zone="bbv2.reference.class.property-set.str">
+ <primary>str</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule str ( )</code>
+ <para>Returns the string repesentation of the stored properties.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.propagated">
+ <indexterm zone="bbv2.reference.class.property-set.propagated">
+ <primary>propagated</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule propagated ( )</code>
+ <para>
+ Returns a <link linkend="bbv2.reference.class.property-set">property-set</link>
+ containing all the <link linkend="bbv2.reference.features.attributes.propagated">propagated</link>
+ properties in this <link linkend="bbv2.reference.class.property-set">property-set</link>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.add">
+ <indexterm zone="bbv2.reference.class.property-set.add">
+ <primary>add</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule add ( ps )</code>
+ <para>
+ Returns a new <link linkend="bbv2.reference.class.property-set">
+ property-set</link> containing the union of the properties
+ in this <link linkend="bbv2.reference.class.property-set">
+ property-set</link> and in <literal>ps</literal>.
+ <note>
+ <para>
+ If <literal>ps</literal> contains non-free properties
+ that should override the values in this object, use
+ <link linkend="bbv2.reference.class.property-set.refine">
+ refine</link> instead.
+ </para>
+ </note>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.add-raw">
+ <indexterm zone="bbv2.reference.class.property-set.add-raw">
+ <primary>add-raw</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule add-raw ( properties * )</code>
+ <para>
+ Link <link linkend="bbv2.reference.class.property-set.add">
+ add</link>, except that it takes a list of properties
+ instead of a <link linkend="bbv2.reference.class.property-set">
+ property-set</link>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.refine">
+ <indexterm zone="bbv2.reference.class.property-set.refine">
+ <primary>refine</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule refine ( ps )</code>
+ <para>
+ Refines properties by overriding any non-free and non-conditional
+ properties for which a different value is specified in
+ <literal>ps</literal>. Returns the resulting
+ <link linkend="bbv2.reference.class.property-set">property-set</link>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.property-set.get">
+ <indexterm zone="bbv2.reference.class.property-set.get">
+ <primary>get</primary>
+ <secondary>Property Set Method</secondary>
+ </indexterm>
+ <code language="jam">rule get ( feature )</code>
+ <para>
+ Returns all the values of <literal>feature</literal>.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/reference.xml b/tools/build/v2/doc/src/reference.xml
index 80775aaceb..deee17c980 100644
--- a/tools/build/v2/doc/src/reference.xml
+++ b/tools/build/v2/doc/src/reference.xml
@@ -45,7 +45,7 @@ rule boost-build ( location ? )
boost-build build-system ;
</programlisting>
- In this case, running bjam anywhere in the project tree will
+ In this case, running <command>b2</command> anywhere in the project tree will
automatically find the build system.</para>
<para>The default <filename>bootstrap.jam</filename>, after loading some standard
@@ -126,7 +126,7 @@ boost-build build-system ;
<link linkend="bbv2.main-target-rule-syntax">common syntax</link>.</para></listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="bbv2.reference.rules.glob">
<term><literal>glob</literal></term>
<listitem><para>The <code>glob</code> rule takes a list shell pattern
@@ -178,7 +178,7 @@ ECHO [ glob-tree *.cpp : .svn ] ;
</para></listitem>
</varlistentry>
- <varlistentry>
+ <varlistentry id="bbv2.reference.rules.explicit">
<term><literal>explicit</literal></term>
<listitem><para>The <literal>explicit</literal> rule takes a single
@@ -227,13 +227,13 @@ constant VERSION : 1.34.0 ;
<listitem><para>Same as <literal>constant</literal> except that
the value is treated as path relative to Jamfile location. For example,
- if <command>bjam</command> is invoked in the current directory,
+ if <command>b2</command> is invoked in the current directory,
and Jamfile in <filename>helper</filename> subdirectory has:
<programlisting>
path-constant DATA : data/a.txt ;
</programlisting>
then the variable <varname>DATA</varname> will be set to
- <literal>helper/data/a.txt</literal>, and if <command>bjam</command>
+ <literal>helper/data/a.txt</literal>, and if <command>b2</command>
is invoked from the <filename>helper</filename> directory, then
the variable <varname>DATA</varname> will be set to
<literal>data/a.txt</literal>.
@@ -411,7 +411,7 @@ path-constant DATA : data/a.txt ;
feature, except that it takes effect only for linking. When you want
to link all targets in a Jamfile to certain library, the
<code>&lt;library&gt;</code> feature is preferred over
- <code>&lt;source&gt;X</code> -- the latter will add the library to
+ <code>&lt;source&gt;X</code>&mdash;the latter will add the library to
all targets, even those that have nothing to do with libraries.
</simpara>
</listitem>
@@ -455,6 +455,20 @@ path-constant DATA : data/a.txt ;
</listitem>
</varlistentry>
+ <varlistentry><term><anchor id="bbv2.builtin.features.implicit-dependency"/>
+ <literal>implicit-dependency</literal></term>
+ <indexterm><primary>implicit-dependency</primary></indexterm>
+
+ <listitem>
+ <simpara>
+ Indicates that the target named by the value of this feature
+ may produce files that are included by the sources of the
+ target being declared. See <xref linkend="bbv2.reference.generated_headers"/>
+ for more information.
+ </simpara>
+ </listitem>
+ </varlistentry>
+
<varlistentry><term><anchor id="bbv2.builtin.features.use"/>
<literal>use</literal></term>
@@ -1761,6 +1775,194 @@ using fop : <optional><replaceable>fop-command</replaceable></optional> : <optio
</section>
+ <section id="bbv2.reference.modules">
+ <title>Builtin modules</title>
+
+ <para>
+ This section describes the modules that are provided
+ by Boost.Build. The import rule allows rules from
+ one module to be used in another module or Jamfile.
+ </para>
+
+ <section id="bbv2.reference.modules.modules">
+ <title>modules</title>
+ <indexterm><primary>modules</primary></indexterm>
+
+ <para>
+ The <code>modules</code> module defines basic functionality
+ for handling modules.
+ </para>
+
+ <para>
+ A module defines a number of rules that can be used in other
+ modules. Modules can contain code at the top level to initialize
+ the module. This code is executed the first time the
+ module is loaded.
+ <note>
+ <para>
+ A Jamfile is a special kind of module which is managed by
+ the build system. Although they cannot be loaded directly
+ by users, the other features of modules are still useful
+ for Jamfiles.
+ </para>
+ </note>
+ </para>
+
+ <para>
+ Each module has its own namespaces for variables and rules. If two
+ modules A and B both use a variable named X, each one gets its own
+ copy of X. They won't interfere with each other in any way.
+ Similarly, importing rules into one module has no effect on any other
+ module.
+ </para>
+
+ <para>
+ Every module has two special variables.
+ <code>$(__file__)</code> contains the name of the file that
+ the module was loaded from and <code>$(__name__)</code>
+ contains the name of the module.
+ <note><para><code>$(__file__)</code> does not contain
+ the full path to the file. If you need this, use
+ <code>modules.binding</code>.</para></note>
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.modules.modules.binding">
+ <indexterm zone="bbv2.reference.modules.modules.binding"><primary>binding</primary></indexterm>
+ <code language="jam">rule binding ( module-name )</code>
+ <para>Returns the filesystem binding of the given module.</para>
+ <para>For example, a module can get its own location with:
+ <programlisting language="jam">me = [ modules.binding $(__name__) ] ;</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.poke">
+ <indexterm zone="bbv2.reference.modules.modules.poke"><primary>poke</primary></indexterm>
+ <code language="jam">rule poke ( module-name ? : variables + : value * )</code>
+ <para>Sets the module-local value of a variable.</para>
+ <para>For example, to set a variable in the global module:
+ <programlisting language="jam">modules.poke : ZLIB_INCLUDE : /usr/local/include ;</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.peek">
+ <indexterm zone="bbv2.reference.modules.modules.peek"><primary>peek</primary></indexterm>
+ <code language="jam">rule peek ( module-name ? : variables + )</code>
+ <para>Returns the module-local value of a variable.</para>
+ <para>
+ For example, to read a variable from the global module:
+ <programlisting language="jam">local ZLIB_INCLUDE = [ modules.peek : ZLIB_INCLUDE ] ;</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.call-in">
+ <indexterm zone="bbv2.reference.modules.modules.call-in"><primary>call-in</primary></indexterm>
+ <code language="jam">rule call-in ( module-name ? : rule-name args * : * ) </code>
+ <para>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><para>rules called this way may accept at most
+ 8 parameters.</para></note></para>
+ <para>Example:
+<programlisting language="jam">
+rule filter ( f : values * )
+{
+ local m = [ CALLER_MODULE ] ;
+ local result ;
+ for v in $(values)
+ {
+ if [ modules.call-in $(m) : $(f) $(v) ]
+ {
+ result += $(v) ;
+ }
+ }
+ return result ;
+}
+</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.load">
+ <indexterm zone="bbv2.reference.modules.modules.load"><primary>load</primary></indexterm>
+ <code language="jam">rule load ( module-name : filename ? : search * )</code>
+ <para>Load the indicated module if it is not already loaded.</para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>module-name</literal></term>
+ <listitem><para>Name of module to load.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><literal>filename</literal></term>
+ <listitem><para>(partial) path to file; Defaults to <code>$(module-name).jam</code></para></listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term><literal>search</literal></term>
+ <listitem><para>Directories in which to search for filename.
+ Defaults to <code>$(BOOST_BUILD_PATH)</code>.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.import">
+ <indexterm zone="bbv2.reference.modules.modules.import"><primary>import</primary></indexterm>
+ <code language="jam">rule import ( module-names + : rules-opt * : rename-opt * )</code>
+ <para>Load the indicated module and import rule names into the
+ current module. Any members of <code>rules-opt</code> will be
+ available without qualification in the caller's module. Any
+ members of <code>rename-opt</code> will be taken as the names
+ of the rules in the caller's module, in place of the names they
+ have in the imported module. If <code>rules-opt = '*'</code>,
+ all rules from the indicated module are imported into the
+ caller's module. If <code>rename-opt</code> is supplied, it must have the
+ same number of elements as <code>rules-opt</code>.</para>
+ <note><para>The <literal>import</literal> rule is available
+ without qualification in all modules.</para></note>
+ <para>Examples:
+<programlisting language="jam">
+import path ;
+import path : * ;
+import path : join ;
+import path : native make : native-path make-path ;
+</programlisting>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.modules.clone-rules">
+ <indexterm zone="bbv2.reference.modules.modules.clone-rules"><primary>clone-rules</primary></indexterm>
+ <code language="jam">rule clone-rules ( source-module target-module )</code>
+ <para>Define exported copies in <code>$(target-module)</code>
+ of all rules exported from <code>$(source-module)</code>. Also
+ make them available in the global module with qualification,
+ so that it is just as though the rules were defined originally
+ in <code>$(target-module)</code>.</para>
+ </listitem>
+
+ </orderedlist>
+
+ </section>
+
+ <xi:include href="path.xml"/>
+ <xi:include href="type.xml"/>
+
+ </section>
+
+ <section id="bbv2.reference.class">
+ <title>Builtin classes</title>
+ <xi:include href="abstract-target.xml"/>
+ <xi:include href="project-target.xml"/>
+ <xi:include href="main-target.xml"/>
+ <xi:include href="basic-target.xml"/>
+ <xi:include href="typed-target.xml"/>
+ <xi:include href="property-set.xml"/>
+ </section>
+
<section id="bbv2.reference.buildprocess">
<title>Build process</title>
@@ -1883,7 +2085,46 @@ exe a : a.cpp
</programlisting>
</para>
- </section>
+ </section>
+
+ <section id="bbv2.reference.buildprocess.targetpath">
+ <title>Target Paths</title>
+
+ <para>Several factors determine the location of a concrete
+ file target. All files in a project are built under
+ the directory bin unless this is overriden by the build-dir project
+ attribute. Under bin is a path that depends on the properties
+ used to build each target. This path is uniquely determined by
+ all non-free, non-incidental properties. For example,
+ given a property set containing:
+ <code>&lt;toolset&gt;gcc &lt;toolset-gcc:version&gt;4.6.1 &lt;variant&gt;debug
+ &lt;warnings&gt;all &lt;define&gt;_DEBUG &lt;include&gt;/usr/local/include
+ &lt;link&gt;static</code>,
+ the path will be gcc-4.6.1/debug/link-static. &lt;warnings&gt; is an
+ incidental feature and &lt;define&gt; and &lt;include&gt; are
+ free features, so they do not affect the path.</para>
+
+ <para>Sometimes the paths produced by Boost.Build can become excessively
+ long. There are a couple of command line options that can help with this.
+ --abbreviate-paths reduces each element to no more than five characters.
+ For example, link-static becomes lnk-sttc. The --hash option reduces the
+ path to a single directory using an MD5 hash.</para>
+
+ <para>There are two features that affect the build
+ directory. The &lt;location&gt; feature completely
+ overrides the default build directory. For example,
+ <programlisting>exe a : a.cpp : &lt;location&gt;. ;</programlisting>
+ builds all the files produced by <code>a</code>
+ in the directory of the Jamfile. This is generally
+ discouraged, as it precludes variant builds.</para>
+
+ <para>The &lt;location-prefix&gt; feature adds a
+ prefix to the path, under the project's build
+ directory. For example,
+ <programlisting>exe a : a.cpp : &lt;location-prefix&gt;subdir ;</programlisting>
+ will create the files for <code>a</code> in bin/subdir/gcc-4.6.1/debug</para>
+
+ </section>
</section>
@@ -1985,7 +2226,7 @@ exe a : a.cpp
<para>Non-incidental features are assumed to affect build
products, so the files for targets whose build specification
differs in non-incidental features are placed in different
- directories as described in "target paths" below. [ where? ]
+ directories as described in <xref linkend="bbv2.reference.buildprocess.targetpath"/>.
</para>
</listitem>
@@ -2041,14 +2282,11 @@ exe a : a.cpp
<listitem>
<para><emphasis>symmetric</emphasis></para>
- <para>A symmetric feature's default value is not automatically
- included in <link linkend=
- "bbv2.reference.variants">build variants</link>. Normally
- a feature only generates a subvariant directory when its
- value differs from the value specified by the build variant,
+ <para>Normally a feature only generates a subvariant directory
+ when its value differs from its default value,
leading to an assymmetric subvariant directory structure for
- certain values of the feature. A symmetric feature, when
- relevant to the toolset, always generates a corresponding
+ certain values of the feature. A symmetric feature
+ always generates a corresponding
subvariant directory.</para>
</listitem>
@@ -2124,24 +2362,6 @@ rule feature ( name : allowed-values * : attributes * )
</section>
</section>
- <section id="bbv2.reference.variants">
- <title>Build Variants</title>
-
- <para>
- A build variant, or (simply variant) is a special kind of composite
- feature that automatically incorporates the default values of
- features that . Typically you'll want at least two separate
- variants: one for debugging, and one for your release code. [
- Volodya says: "Yea, we'd need to mention that it's a composite
- feature and describe how they are declared, in pacticular that
- default values of non-optional features are incorporated into
- build variant automagically. Also, do we wan't some variant
- inheritance/extension/templates. I don't remember how it works in
- V1, so can't document this for V2.". Will clean up soon -DWA ]
- </para>
-
- </section>
-
<section id="bbv2.reference.variants.proprefine">
<title>Property refinement</title>
diff --git a/tools/build/v2/doc/src/standalone.xml b/tools/build/v2/doc/src/standalone.xml
index eea5e101da..22ffff1ee1 100644
--- a/tools/build/v2/doc/src/standalone.xml
+++ b/tools/build/v2/doc/src/standalone.xml
@@ -3,7 +3,7 @@
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude"
- id="bbv2" last-revision="$Date: 2011-01-25 13:06:12 -0500 (Tue, 25 Jan 2011) $">
+ id="bbv2" last-revision="$Date: 2011-01-25 10:06:12 -0800 (Tue, 25 Jan 2011) $">
<bookinfo>
<copyright>
<year>2006</year>
diff --git a/tools/build/v2/doc/src/tasks.xml b/tools/build/v2/doc/src/tasks.xml
index 2b3e68bd16..d6419d4d8f 100644
--- a/tools/build/v2/doc/src/tasks.xml
+++ b/tools/build/v2/doc/src/tasks.xml
@@ -28,7 +28,7 @@ exe hello : hello.cpp some_library.lib /some_project//library
: &lt;threading&gt;multi
;
</programlisting>
- This will create an executable file from the sources -- in this case, one
+ This will create an executable file from the sources&mdash;in this case, one
C++ file, one library file present in the same directory, and another
library that is created by Boost.Build. Generally, sources can include C
and C++ files, object files and libraries. Boost.Build will automatically
@@ -54,6 +54,11 @@ exe hello : hello.cpp some_library.lib /some_project//library
<section id="bbv2.tasks.libraries">
<title>Libraries</title>
+ <indexterm>
+ <primary>library</primary>
+ <secondary>target</secondary>
+ </indexterm>
+
<para>
Library targets are created using the <code>lib</code> rule, which
follows the <link linkend="bbv2.main-target-rule-syntax">common syntax
@@ -63,66 +68,71 @@ lib helpers : helpers.cpp ;
</programlisting>
This will define a library target named <code>helpers</code> built from
the <code>helpers.cpp</code> source file.
+ It can be either a static library or a shared library,
+ depending on the value of the <link linkend="bbv2.overview.builtins.features.link">&lt;link&gt;</link> feature.
</para>
<para>
- Depending on the given &lt;link&gt; feature value the library will be
- either static or shared.
- </para>
- <para>
- Library targets may be used to represent:
+ Library targets can represent:
<itemizedlist>
<listitem>
<para>
- <code>Built libraries</code> that get built from specified sources,
- as is the one in the example above. <!-- add link -->
+ Libraries that should be built from source,
+ as in the example above.
</para>
</listitem>
<listitem>
<para>
- <code>Prebuilt libraries</code> which already exist on the system
- and are just supposed to be used by the build system. Such
- libraries may be searched for by the tools using them (typically
- linkers referencing the library using the <option>-l</option>
- option) or their path may be known in advance by the build system.
- <!-- We need examples for this. -->
+ Prebuilt libraries which already exist on the system.
+ Such libraries can be searched for by the tools using them (typically
+ with the linker's <option>-l</option> option) or their paths can be
+ known in advance by the build system.
</para>
</listitem>
</itemizedlist>
</para>
<para>
- The syntax for these case is given below:
+ The syntax for prebuilt libraries is given below:
<programlisting>
lib z : : &lt;name&gt;z &lt;search&gt;/home/ghost ;
lib compress : : &lt;file&gt;/opt/libs/compress.a ;
</programlisting>
- The <code>name</code> property specifies the name that should be passed to
- the <option>-l</option> option, and the <code>file</code> property
- specifies the file location. The <varname>search</varname> feature
- specifies paths in which to search for the library. That feature can be
- specified several times or it can be omitted, in which case only the
- default compiler paths will be searched.
- </para>
-
- <para>
- The difference between using the <varname>file</varname> feature as
- opposed to the <varname>name</varname> feature together with the <varname>
- search</varname> feature is that <varname>file</varname> is more precise.
- A specific file will be used as opposed to the <varname>search</varname>
- feature only adding a library path, or the <varname>name</varname> feature
- giving only the basic name of the library. The search rules are specific
- to the linker used. For example, given these definition:
+ The <code>name</code> property specifies the name of the library
+ without the standard prefixes and suffixes. For example, depending
+ on the system, <code>z</code> could refer to a file called
+ z.so, libz.a, or z.lib, etc. The <code>search</code> feature
+ specifies paths in which to search for the library in addition
+ to the default compiler paths. <code>search</code> can be specified
+ several times or it can be omitted, in which case only the default
+ compiler paths will be searched. The <code>file</code> property
+ specifies the file location.
+ </para>
+
+ <para>
+ The difference between using the <code>file</code> feature and
+ using a combination of the <code>name</code> and <code>search</code>
+ features is that <code>file</code> is more precise.
+
+ <warning>
+ <para>
+ The value of the <code>search</code> feature is just added to the
+ linker search path. When linking to multiple libraries,
+ the paths specified by <code>search</code> are combined without
+ regard to which <code>lib</code> target each path came from.
+ Thus, given
<programlisting>
-lib a : : &lt;variant&gt;release &lt;file&gt;/pool/release/a.so ;
-lib a : : &lt;variant&gt;debug &lt;file&gt;/pool/debug/a.so ;
-lib b : : &lt;variant&gt;release &lt;file&gt;/pool/release/b.so ;
-lib b : : &lt;variant&gt;debug &lt;file&gt;/pool/debug/b.so ;
+lib a : : &lt;name&gt;a &lt;search&gt;/pool/release ;
+lib b : : &lt;name&gt;b &lt;search&gt;/pool/debug ;
</programlisting>
- It is possible to use a release version of <code>a</code> and debug
- version of <code>b</code>. Had we used the <varname>name</varname> and
- <varname>search</varname> features, the linker would have always picked
- either the release or the debug versions.
- <!-- explain -->
+ If /pool/release/a.so, /pool/release/b.so, /pool/debug/a.so,
+ and /pool/release/b.so all exist, the linker will probably
+ take both <code>a</code> and <code>b</code> from the same
+ directory, instead of finding <code>a</code> in /pool/release
+ and <code>b</code> in /pool/debug. If you need to distinguish
+ between multiple libraries with the same name, it's safer
+ to use <code>file</code>.
+ </para>
+ </warning>
</para>
<para>
@@ -154,18 +164,18 @@ lib png : z : &lt;name&gt;png ;
<note>
<para>
- When a library has a shared library defined as its source, or a static
- library has another static library defined as its source then any target
+ When a library has a shared library as a source, or a static
+ library has another static library as a source then any target
linking to the first library with automatically link to its source
library as well.
</para>
<para>
- On the other hand, when a shared library has a static library defined as
- its source then the first library will be built so that it completely
+ On the other hand, when a shared library has a static library as
+ a source then the first library will be built so that it completely
includes the second one.
</para>
<para>
- If you do not want shared libraries to include all libraries specified
+ If you do not want a shared library to include all the libraries specified
in its sources (especially statically linked ones), you would need to
use the following:
<programlisting>
@@ -173,18 +183,16 @@ lib b : a.cpp ;
lib a : a.cpp : &lt;use&gt;b : : &lt;library&gt;b ;
</programlisting>
This specifies that library <code>a</code> uses library <code>b</code>,
- and causes all executables that link to <code>a</code> also link to
- <code>b</code>. In this case, even for shared linking, the
- <code>a</code> library will not even refer to <code>b</code>.
+ and causes all executables that link to <code>a</code> to link to
+ <code>b</code> also. In this case, even for shared linking, the
+ <code>a</code> library will not refer to <code>b</code>.
</para>
</note>
<para>
- One Boost.Build feature that is often very useful for defining library
- targets are usage requirements. <!-- Rephrase that. But then, it is much
- too late for an introduction of usage requirements - you have already
- discussed them many times. Also, add references to the sections describing
- requirements and usage-requirements here. --> For example, imagine that
+ <!-- FIXME: After adding a full subsection on usage requirements, link to it -->
+ <link linkend="bbv2.overview.targets">Usage requirements</link> are often
+ very useful for defining library targets. For example, imagine that
you want you build a <code>helpers</code> library and its interface is
described in its <code>helpers.hpp</code> header file located in the same
directory as the <code>helpers.cpp</code> source file. Then you could add
@@ -203,7 +211,7 @@ lib helpers : helpers.cpp : : : &lt;include&gt;. ;
<title>Alias</title>
<para>
- The <functionname>alias</functionname> rule gives an alternative name to a
+ The <code language="jam">alias</code> rule gives an alternative name to a
group of targets. For example, to give the name <filename>core</filename>
to a group of three other targets with the following code:
<programlisting>
@@ -384,8 +392,8 @@ unit-test helpers_test : helpers_test.cpp helpers ;
</para>
<para>
- The <functionname>unit-test</functionname> rule behaves like the
- <functionname>exe</functionname> rule, but after the executable is created
+ The <code language="jam">unit-test</code> rule behaves like the
+ <link linkend="bbv2.tasks.programs">exe</link> rule, but after the executable is created
it is also run. If the executable returns an error code, the build system
will also return an error and will try running the executable on the next
invocation until it runs successfully. This behaviour ensures that you can
@@ -476,8 +484,8 @@ boost-test(<replaceable>test-type</replaceable>) <replaceable>path</replaceable>
</para>
<para>
- It is possible to process the list of tests, the output of bjam during
- command run, and the presense/absense of the <filename>*.test</filename>
+ It is possible to process the list of tests, Boost.Build output
+ and the presense/absense of the <filename>*.test</filename>
files created when test passes into human-readable status table of tests.
Such processing utilities are not included in Boost.Build.
</para>
@@ -487,33 +495,33 @@ boost-test(<replaceable>test-type</replaceable>) <replaceable>path</replaceable>
<title>Custom commands</title>
<para>
- When you use most of main target rules, Boost.Build automatically figures
- what commands to run and it what order. As soon as you want to use new
+ For most main target rules, Boost.Build automatically figures out
+ the commands to run. When you want to use new
file types or support new tools, one approach is to extend Boost.Build to
- smoothly support them, as documented in <xref linkend="bbv2.extender"/>.
- However, if there is only a single place where the new tool is used, it
- might be easier to just explicitly specify the commands to run.
+ support them smoothly, as documented in <xref linkend="bbv2.extender"/>.
+ However, if the new tool is only used in a single place, it
+ might be easier just to specify the commands to run explicitly.
</para>
<para>
<!-- This paragraph requires links to where the terms 'virtual target' &
'target' are defined. -->
- Three main target rules can be used for that. The <functionname>make
- </functionname> rule allows you to construct a single file from any number
- of source file, by running a command you specify. The <functionname>
- notfile</functionname> rule allows you to run an arbitrary command,
- without creating any files. And finaly, the <functionname>generate
- </functionname> rule allows you to describe transformation using
- Boost.Build's virtual targets. This is higher-level than file names that
- the <functionname>make</functionname> rule operates with and allows you to
+ Three main target rules can be used for that. The <code language="jam">make
+ </code> rule allows you to construct a single file from any number
+ of source file, by running a command you specify. The <code language="jam">
+ notfile</code> rule allows you to run an arbitrary command,
+ without creating any files. And finaly, the <code language="jam">generate
+ </code> rule allows you to describe a transformation using
+ Boost.Build's virtual targets. This is higher-level than the file names that
+ the <code language="jam">make</code> rule operates with and allows you to
create more than one target, create differently named targets depending on
properties or use more than one tool.
</para>
<para>
- The <functionname>make</functionname> rule is used when you want to create
+ The <code language="jam">make</code> rule is used when you want to create
one file from a number of sources using some specific command. The
- <functionname>notfile</functionname> is used to unconditionally run a
+ <code language="jam">notfile</code> is used to unconditionally run a
command.
</para>
@@ -524,8 +532,8 @@ boost-test(<replaceable>test-type</replaceable>) <replaceable>path</replaceable>
them to become accessible. -->
<para>
- Suppose you want to create file <filename>file.out</filename> from file
- <filename>file.in</filename> by running command <command>
+ Suppose you want to create the file <filename>file.out</filename> from
+ the file <filename>file.in</filename> by running the command <command>
in2out</command>. Here is how you would do this in Boost.Build:
<programlisting>
make file.out : file.in : @in2out ;
@@ -534,7 +542,7 @@ actions in2out
in2out $(&lt;) $(&gt;)
}
</programlisting>
- If you run <command>bjam</command> and <filename>file.out</filename> does
+ If you run <command>b2</command> and <filename>file.out</filename> does
not exist, Boost.Build will run the <command>in2out</command> command to
create that file. For more details on specifying actions, see <xref
linkend="bbv2.overview.jam_language.actions"/>.
@@ -543,7 +551,7 @@ actions in2out
<para>
It could be that you just want to run some command unconditionally, and
that command does not create any specific files. For that you can use the
- <functionname>notfile</functionname> rule. For example:
+ <code language="jam">notfile</code> rule. For example:
<programlisting>
notfile echo_something : @echo ;
actions echo
@@ -551,7 +559,7 @@ actions echo
echo "something"
}
</programlisting>
- The only difference from the <functionname>make</functionname> rule is
+ The only difference from the <code language="jam">make</code> rule is
that the name of the target is not considered a name of a file, so
Boost.Build will unconditionally run the action.
</para>
@@ -559,9 +567,9 @@ actions echo
<para>
<!-- This paragraph requires links to where terms like 'virtual target',
'target', 'project-target' & 'property-set' are defined. -->
- The <functionname>generate</functionname> rule is used when you want to
+ The <code language="jam">generate</code> rule is used when you want to
express transformations using Boost.Build's virtual targets, as opposed to
- just filenames. The <functionname>generate</functionname> rule has the
+ just filenames. The <code language="jam">generate</code> rule has the
standard main target rule signature, but you are required to specify the
<literal>generating-rule</literal> property. The value of the property
should be in the form <literal>
@@ -620,7 +628,7 @@ rule generating-rule ( project name : property-set : sources * )
cpp-pch pch : pch.hpp ;
exe main : main.cpp pch ;
</programlisting>
- You can use the <functionname>c-pch</functionname> rule if you want to
+ You can use the <code language="jam">c-pch</code> rule if you want to
use the precompiled header in C programs.
</para></listitem>
</orderedlist>
@@ -704,7 +712,7 @@ exe main : main.cpp pch ;
Making this mechanism work across main target boundaries is possible, but
imposes certain overhead. For that reason, if there is implicit dependency
on files from other main targets, the <literal>&lt;implicit-dependency&gt;
- </literal> [ link ] feature must be used, for example:
+ </literal> feature must be used, for example:
<programlisting>
lib parser : parser.y ;
exe app : app.cpp : &lt;implicit-dependency&gt;parser ;
@@ -735,7 +743,7 @@ using gcc : arm : arm-none-linux-gnueabi-g++ ;
just request that this compiler version to be used:
</para>
<screen>
-bjam toolset=gcc-arm
+b2 toolset=gcc-arm
</screen>
<para>
@@ -745,9 +753,9 @@ bjam toolset=gcc-arm
</para>
<screen>
# On windows box
-bjam toolset=gcc-arm <emphasis role="bold">target-os=linux</emphasis>
+b2 toolset=gcc-arm <emphasis role="bold">target-os=linux</emphasis>
# On Linux box
-bjam toolset=gcc-mingw <emphasis role="bold">target-os=windows</emphasis>
+b2 toolset=gcc-mingw <emphasis role="bold">target-os=windows</emphasis>
</screen>
<para>
For the complete list of allowed opeating system names, please see the documentation for
diff --git a/tools/build/v2/doc/src/tutorial.xml b/tools/build/v2/doc/src/tutorial.xml
index 3763471dfe..141ed9196f 100644
--- a/tools/build/v2/doc/src/tutorial.xml
+++ b/tools/build/v2/doc/src/tutorial.xml
@@ -30,33 +30,33 @@
<filename>example/hello/</filename> directory. The project is described by
a file called <filename>Jamroot</filename> that contains:
-<programlisting>
+<programlisting language="jam">
exe hello : hello.cpp ;
</programlisting>
Even with this simple setup, you can do some interesting things. First of
- all, just invoking <command>bjam</command> will build the <filename>hello
+ all, just invoking <command>b2</command> will build the <filename>hello
</filename> executable by compiling and linking <filename>hello.cpp
- </filename>. By default, debug variant is built. Now, to build the release
+ </filename>. By default, the debug variant is built. Now, to build the release
variant of <filename>hello</filename>, invoke
<screen>
-bjam release
+b2 release
</screen>
- Note that debug and release variants are created in different directories,
+ Note that the debug and release variants are created in different directories,
so you can switch between variants or even build multiple variants at
once, without any unnecessary recompilation. Let us extend the example by
adding another line to our project's <filename>Jamroot</filename>:
-<programlisting>
+<programlisting language="jam">
exe hello2 : hello.cpp ;
</programlisting>
Now let us build both the debug and release variants of our project again:
<screen>
-bjam debug release
+b2 debug release
</screen>
Note that two variants of <filename>hello2</filename> are linked. Since we
@@ -66,7 +66,7 @@ bjam debug release
let us remove all the built products:
<screen>
-bjam --clean debug release
+b2 --clean debug release
</screen>
It is also possible to build or clean specific targets. The following two
@@ -74,8 +74,8 @@ bjam --clean debug release
<filename>hello2</filename>.
<screen>
-bjam hello2
-bjam --clean hello2
+b2 hello2
+b2 --clean hello2
</screen>
</para>
</section>
@@ -84,9 +84,9 @@ bjam --clean hello2
<title>Properties</title>
<para>
- To portably represent aspects of target configuration such as
+ To represent aspects of target configuration such as
debug and release variants, or single- and multi-threaded
- builds, Boost.Build uses <firstterm>features</firstterm> with
+ builds portably, Boost.Build uses <firstterm>features</firstterm> with
associated <firstterm>values</firstterm>. For
example, the <code>debug-symbols</code> feature can have a value of <code>on</code> or
<code>off</code>. A <firstterm>property</firstterm> is just a (feature,
@@ -102,7 +102,7 @@ bjam --clean hello2
builds the project's <code>release</code> variant with inlining
disabled and debug symbols enabled:
<screen>
-bjam release inlining=off debug-symbols=on
+b2 release inlining=off debug-symbols=on
</screen>
</para>
@@ -116,19 +116,19 @@ bjam release inlining=off debug-symbols=on
<para>
The <option>release</option> and <option>debug</option> that we have seen
- in <command>bjam</command> invocations are just a shorthand way to specify
+ in <command>b2</command> invocations are just a shorthand way to specify
values of the <varname>variant</varname> feature. For example, the
command above could also have been written this way:
<screen>
-bjam variant=release inlining=off debug-symbols=on
+b2 variant=release inlining=off debug-symbols=on
</screen>
</para>
<para>
<varname>variant</varname> is so commonly-used that it has been given
special status as an <firstterm>implicit</firstterm> feature&#x2014;
- Boost.Build will deduce the its identity just from the name of one of its
+ Boost.Build will deduce its identity just from the name of one of its
values.
</para>
@@ -140,7 +140,7 @@ bjam variant=release inlining=off debug-symbols=on
<title>Build Requests and Target Requirements</title>
<para>
- The set of properties specified on the command line constitute
+ The set of properties specified on the command line constitutes
a <firstterm>build request</firstterm>&#x2014;a description of
the desired properties for building the requested targets (or,
if no targets were explicitly requested, the project in the
@@ -160,7 +160,7 @@ bjam variant=release inlining=off debug-symbols=on
illustrates how these requirements might be specified.
</para>
-<programlisting>
+<programlisting language="jam">
exe hello
: hello.cpp
: &lt;include&gt;boost &lt;threading&gt;multi
@@ -170,7 +170,7 @@ exe hello
<para>
When <filename>hello</filename> is built, the two requirements specified
above will always be present. If the build request given on the
- <command>bjam</command> command-line explictly contradicts a target's
+ <command>b2</command> command-line explictly contradicts a target's
requirements, the target requirements usually override (or, in the case
of &#x201C;free&rdquo;&#x201D; features like
<varname>&lt;include&gt;</varname>,
@@ -195,14 +195,15 @@ exe hello
<title>Project Attributes</title>
<para>
- If we want the same requirements for our other target, <filename>hello2
- </filename>, we could simply duplicate them. However, as projects grow,
- that approach leads to a great deal of repeated boilerplate in Jamfiles.
+ If we want the same requirements for our other target,
+ <filename>hello2</filename>, we could simply duplicate them. However,
+ as projects grow, that approach leads to a great deal of repeated
+ boilerplate in Jamfiles.
Fortunately, there's a better way. Each project can specify a set of
<firstterm>attributes</firstterm>, including requirements:
-<programlisting>
+<programlisting language="jam">
project
: requirements &lt;include&gt;/home/ghost/Work/boost &lt;threading&gt;multi
;
@@ -220,8 +221,8 @@ exe hello2 : hello.cpp ;</programlisting>
<title>Project Hierarchies</title>
<para>
- So far we have only considered examples with one project &#x2014;a. with
- one user-written Boost.Jam file, <filename>Jamroot</filename>). A typical
+ So far we have only considered examples with one project, with
+ one user-written Boost.Jam file, <filename>Jamroot</filename>. A typical
large codebase would be composed of many projects organized into a tree.
The top of the tree is called the <firstterm>project root</firstterm>.
Every subproject is defined by a file called <filename>Jamfile</filename>
@@ -271,7 +272,7 @@ top/
any requirements specified by the subproject.
For example, if <filename>top/Jamroot</filename> has
-<programlisting>
+<programlisting language="jam">
&lt;include&gt;/home/ghost/local
</programlisting>
@@ -289,14 +290,14 @@ top/
</para>
<para>
- Invoking <command>bjam</command> without explicitly specifying
+ Invoking <command>b2</command> without explicitly specifying
any targets on the command line builds the project rooted in the
current directory. Building a project does not automatically
cause its subprojects to be built unless the parent project's
Jamfile explicitly requests it. In our example,
<filename>top/Jamroot</filename> might contain:
-<programlisting>
+<programlisting language="jam">
build-project app ;
</programlisting>
@@ -312,7 +313,7 @@ build-project app ;
<title>Dependent Targets</title>
<para>
- When a building a target <filename>X</filename> depends on first
+ When building a target <filename>X</filename> that depends on first
building another target <filename>Y</filename> (such as a
library that must be linked with <firstterm>X</firstterm>),
<filename>Y</filename> is called a
@@ -326,14 +327,14 @@ build-project app ;
use libraries from <filename>top/util/foo</filename>. If
<filename>top/util/foo/Jamfile</filename> contains
-<programlisting>
+<programlisting language="jam">
lib bar : bar.cpp ;
</programlisting>
then to use this library in <filename>top/app/Jamfile</filename>, we can
write:
-<programlisting>
+<programlisting language="jam">
exe app : app.cpp ../util/foo//bar ;
</programlisting>
@@ -352,7 +353,7 @@ exe app : app.cpp ../util/foo//bar ;
<para>Suppose we build <filename>app</filename> with:
<screen>
-bjam app optimization=full define=USE_ASM
+b2 app optimization=full define=USE_ASM
</screen>
Which properties will be used to build <code>foo</code>? The answer is
that some features are
@@ -369,13 +370,13 @@ bjam app optimization=full define=USE_ASM
<para>
Let's improve this project further. The library probably has some headers
that must be used when compiling <filename>app.cpp</filename>. We could
- manually add the necessary <code>#include</code> paths to <filename>app
- </filename>'s requirements as values of the <varname>&lt;include&gt;
- </varname> feature, but then this work will be repeated for all programs
- that use <filename>foo</filename>. A better solution is to modify
- <filename>util/foo/Jamfile</filename> in this way:
+ manually add the necessary <code>#include</code> paths to
+ <filename>app</filename>'s requirements as values of the
+ <varname>&lt;include&gt; </varname> feature, but then this work will be
+ repeated for all programs that use <filename>foo</filename>. A better
+ solution is to modify <filename>util/foo/Jamfile</filename> in this way:
- <programlisting>
+ <programlisting language="jam">
project
: usage-requirements &lt;include&gt;.
;
@@ -397,7 +398,7 @@ lib foo : foo.cpp ;</programlisting>
code to <filename>Jamroot</filename>:
</para>
- <programlisting>
+ <programlisting language="jam">
use-project /library-example/foo : util/foo ;</programlisting>
<para>
@@ -424,7 +425,7 @@ exe app : app.cpp /library-example/foo//bar ;</programlisting>
requirements, like this:
</para>
- <programlisting>
+ <programlisting language="jam">
project
: requirements &lt;library&gt;/boost/filesystem//fs
;</programlisting>
@@ -448,9 +449,9 @@ project
<literal>shared</literal>, and to build a static library, the value should
be <literal>static</literal>. You can request a static build either on the
command line:
- <programlisting>bjam link=static</programlisting>
+ <programlisting>b2 link=static</programlisting>
or in the library's requirements:
- <programlisting>lib l : l.cpp : &lt;link&gt;static ;</programlisting>
+ <programlisting language="jam">lib l : l.cpp : &lt;link&gt;static ;</programlisting>
</para>
<para>
@@ -469,10 +470,10 @@ project
VP: to be addressed when this section is moved. See comment below.
-->
- <programlisting>
+ <programlisting language="jam">
exe important : main.cpp helpers/&lt;link&gt;static ;</programlisting>
- No matter what arguments are specified on the <command>bjam</command>
+ No matter what arguments are specified on the <command>b2</command>
command line, <filename>important</filename> will only be linked with the
static version of <filename>helpers</filename>.
</para>
@@ -484,7 +485,7 @@ exe important : main.cpp helpers/&lt;link&gt;static ;</programlisting>
that library is used by many targets, you <emphasis>could</emphasis> use
target references everywhere:
- <programlisting>
+ <programlisting language="jam">
exe e1 : e1.cpp /other_project//bar/&lt;link&gt;static ;
exe e10 : e10.cpp /other_project//bar/&lt;link&gt;static ;</programlisting>
@@ -497,9 +498,9 @@ alias foo : /other_project//bar/&lt;link&gt;static ;
exe e1 : e1.cpp foo ;
exe e10 : e10.cpp foo ;</programlisting>
- The <link linkend="bbv2.tasks.alias"><functionname>alias</functionname>
- </link> rule is specifically used to rename a reference to a target and
- possibly change the properties.
+ The <link linkend="bbv2.tasks.alias">alias</link> rule is specifically
+ used to rename a reference to a target and possibly change the
+ properties.
<!-- You should introduce the alias rule in an earlier section, before
describing how it applies to this specific use-case, and the
@@ -514,7 +515,7 @@ exe e10 : e10.cpp foo ;</programlisting>
<para>
When one library uses another, you put the second library in the source
list of the first. For example:
- <programlisting>
+ <programlisting language="jam">
lib utils : utils.cpp /boost/filesystem//fs ;
lib core : core.cpp utils ;
exe app : app.cpp core ;</programlisting>
@@ -553,14 +554,14 @@ exe app : app.cpp core ;</programlisting>
<code>release</code> variant is built. This can be achieved using
<firstterm>conditional requirements</firstterm>.
- <programlisting>
+ <programlisting language="jam">
lib network : network.cpp
: <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NEWORK_LIB_SHARED</emphasis>
&lt;variant&gt;release:&lt;define&gt;EXTRA_FAST
;</programlisting>
In the example above, whenever <filename>network</filename> is built with
- <code>&lt;link&gt;shared</code>, <code>&lt;define&gt;NEWORK_LIB_SHARED
+ <code language="jam">&lt;link&gt;shared</code>, <code language="jam">&lt;define&gt;NEWORK_LIB_SHARED
</code> will be in its properties, too. Also, whenever its release variant
is built, <code>&lt;define&gt;EXTRA_FAST</code> will appear in its
properties.
@@ -572,15 +573,15 @@ lib network : network.cpp
library actually uses different source files depending on the toolset used
to build it. We can express this situation using <firstterm>target
alternatives</firstterm>:
- <programlisting>
+ <programlisting language="jam">
lib demangler : dummy_demangler.cpp ; # alternative 1
lib demangler : demangler_gcc.cpp : &lt;toolset&gt;gcc ; # alternative 2
lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3</programlisting>
When building <filename>demangler</filename>, Boost.Build will compare
requirements for each alternative with build properties to find the best
- match. For example, when building with <code>&lt;toolset&gt;gcc</code>
+ match. For example, when building with <code language="jam">&lt;toolset&gt;gcc</code>
alternative 2, will be selected, and when building with
- <code>&lt;toolset&gt;msvc</code> alternative 3 will be selected. In all
+ <code language="jam">&lt;toolset&gt;msvc</code> alternative 3 will be selected. In all
other cases, the most generic alternative 1 will be built.
</para>
</section>
@@ -594,7 +595,7 @@ lib demangler : demangler_msvc.cpp : &lt;toolset&gt;msvc ; # alternative 3</prog
<varname>file</varname> property. Target alternatives can be used to
associate multiple library files with a single conceptual target. For
example:
- <programlisting>
+ <programlisting language="jam">
# util/lib2/Jamfile
lib lib2
:
@@ -616,7 +617,7 @@ lib lib2
Once a prebuilt target has been declared, it can be used just like any
other target:
- <programlisting>
+ <programlisting language="jam">
exe app : app.cpp ../util/lib2//lib2 ;</programlisting>
As with any target, the alternative selected depends on the properties
@@ -631,7 +632,7 @@ exe app : app.cpp ../util/lib2//lib2 ;</programlisting>
by searching through some set of predetermined paths&#x2014;should be
declared almost like regular ones:
- <programlisting>
+ <programlisting language="jam">
lib pythonlib : : &lt;name&gt;python22 ;</programlisting>
We again don't specify any sources, but give a <varname>name</varname>
@@ -644,12 +645,12 @@ lib pythonlib : : &lt;name&gt;python22 ;</programlisting>
<para>
We can also specify where the toolset should look for the library:
- <programlisting>
+ <programlisting language="jam">
lib pythonlib : : &lt;name&gt;python22 &lt;search&gt;/opt/lib ;</programlisting>
And, of course, target alternatives can be used in the usual way:
- <programlisting>
+ <programlisting language="jam">
lib pythonlib : : &lt;name&gt;python22 &lt;variant&gt;release ;
lib pythonlib : : &lt;name&gt;python22_d &lt;variant&gt;debug ;</programlisting>
</para>
diff --git a/tools/build/v2/doc/src/type.xml b/tools/build/v2/doc/src/type.xml
new file mode 100644
index 0000000000..6ca7cc7ae1
--- /dev/null
+++ b/tools/build/v2/doc/src/type.xml
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.modules.type">
+
+ <title>type</title>
+ <indexterm>
+ <primary>type</primary>
+ <secondary>module</secondary>
+ </indexterm>
+
+ <para>
+ Deals with target type declaration and defines target class which supports
+ typed targets.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.modules.type.register">
+ <indexterm zone="bbv2.reference.modules.type.register">
+ <primary>register</primary>
+ <secondary>type</secondary>
+ </indexterm>
+ <code language="jam">rule register ( type : suffixes * : base-type ? )</code>
+ <para>
+ Registers a target type, possible derived from a
+ <code language="jam">base-type</code>. Providing a list
+ of suffixes here is a shortcut for separately calling the
+ <link linkend="bbv2.reference.modules.type.register-suffixes">register-suffixes</link>
+ rule with the given suffixes and the
+ <link linkend="bbv2.reference.modules.type.set-generated-target-suffix">set-generated-target-suffix</link>
+ rule with the first given suffix.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.register-suffixes">
+ <indexterm zone="bbv2.reference.modules.type.register-suffixes">
+ <primary>register-suffixes</primary>
+ </indexterm>
+ <code language="jam">rule register-suffixes ( suffixes + : type )</code>
+ <para>
+ Specifies that files with suffix from <code language="jam">suffixes</code>
+ be recognized as targets of type <code language="jam">type</code>.
+ Issues an error if a different type is already specified for any
+ of the suffixes.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.registered">
+ <indexterm zone="bbv2.reference.modules.type.registered">
+ <primary>registered</primary>
+ </indexterm>
+ <code language="jam">rule registered ( type )</code>
+ <para>Returns true iff type has been registered.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.validate">
+ <indexterm zone="bbv2.reference.modules.type.validate">
+ <primary>validate</primary>
+ </indexterm>
+ <code language="jam">rule validate ( type )</code>
+ <para>Issues an error if <code lang="jam">type</code> is unknown.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.set-scanner">
+ <indexterm zone="bbv2.reference.modules.type.set-scanner">
+ <primary>set-scanner</primary>
+ </indexterm>
+ <code language="jam">rule set-scanner ( type : scanner )</code>
+ <para>Sets a scanner class that will be used for this type.</para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.get-scanner">
+ <indexterm zone="bbv2.reference.modules.type.get-scanner">
+ <primary>get-scanner</primary>
+ </indexterm>
+ <code language="jam">rule get-scanner ( type : property-set )</code>
+ <para>
+ Returns a scanner instance appropriate to <code language="jam">type</code>
+ and <code language="jam">property-set</code>.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.base">
+ <indexterm zone="bbv2.reference.modules.type.base">
+ <primary>base</primary>
+ </indexterm>
+ <code language="jam">rule base ( type )</code>
+ <para>
+ Returns a base type for the given type or nothing in case the given
+ type is not derived.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.all-bases">
+ <indexterm zone="bbv2.reference.modules.type.all-bases">
+ <primary>all-bases</primary>
+ </indexterm>
+ <code language="jam">rule all-bases ( type )</code>
+ <para>
+ Returns the given type and all of its base types in order of
+ their distance from type.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.all-derived">
+ <indexterm zone="bbv2.reference.modules.type.all-derived">
+ <primary>all-derived</primary>
+ </indexterm>
+ <code language="jam">rule all-derived ( type )</code>
+ <para>
+ Returns the given type and all of its derived types in order
+ of their distance from type.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.is-derived">
+ <indexterm zone="bbv2.reference.modules.type.is-derived">
+ <primary>is-derived</primary>
+ </indexterm>
+ <code language="jam">rule is-derived ( type base )</code>
+ <para>
+ Returns true if <code language="jam">type</code> is equal to
+ <code language="jam">base</code> or has <code language="jam">base</code>
+ as its direct or indirect base.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.set-generated-target-suffix">
+ <indexterm zone="bbv2.reference.modules.type.set-generated-target-suffix">
+ <primary>set-generated-target-suffix</primary>
+ </indexterm>
+ <code language="jam">rule set-generated-target-suffix ( type : properties * : suffix )</code>
+ <para>
+ Sets a file suffix to be used when generating a target of <code language="jam">type</code> with the
+ specified properties. Can be called with no properties if no suffix has
+ already been specified for the <code language="jam">type</code>. The <code language="jam">suffix</code> parameter can be an empty
+ string (<code language="jam">""</code>) to indicate that no suffix should be used.
+ </para>
+
+ <para>
+ Note that this does not cause files with <code language="jam">suffix</code>
+ to be automatically recognized as being of <code language="jam">type</code>.
+ Two different types can use the same suffix for their generated files
+ but only one type can be auto-detected for a file with that suffix.
+ User should explicitly specify which one using the
+ <link linkend="bbv2.reference.modules.type.register-suffixes">register-suffixes</link>
+ rule.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.change-generated-target-suffix">
+ <indexterm zone="bbv2.reference.modules.type.change-generated-target-suffix">
+ <primary>change-generated-target-suffix</primary>
+ </indexterm>
+ <code language="jam">rule change-generated-target-suffix ( type : properties * : suffix )</code>
+ <para>
+ Change the suffix previously registered for this type/properties
+ combination. If suffix is not yet specified, sets it.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.generated-target-suffix">
+ <indexterm zone="bbv2.reference.modules.type.generated-target-suffix">
+ <primary>generated-target-suffix</primary>
+ </indexterm>
+ <code language="jam">rule generated-target-suffix ( type : property-set )</code>
+ <para>
+ Returns the suffix used when generating a file of
+ <code language="jam">type</code> with the given properties.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.set-generated-target-prefix">
+ <indexterm zone="bbv2.reference.modules.type.set-generated-target-prefix">
+ <primary>set-generated-target-prefix</primary>
+ </indexterm>
+ <code language="jam">rule set-generated-target-prefix ( type : properties * : prefix )</code>
+ <para>
+ Sets a target prefix that should be used when generating targets of
+ <code language="jam">type</code> with the specified properties. Can
+ be called with empty properties if no prefix for
+ <code language="jam">type</code> has been specified yet.
+ </para>
+
+ <para>
+ The <code language="jam">prefix</code> parameter can be empty string
+ (<code language="jam">""</code>) to indicate that no prefix
+ should be used.
+ </para>
+
+ <para>
+ Usage example: library names use the <code language="jam">"lib"</code>
+ prefix on unix.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.change-generated-target-prefix">
+ <indexterm zone="bbv2.reference.modules.type.change-generated-target-prefix">
+ <primary>change-generated-target-prefix</primary>
+ </indexterm>
+ <code language="jam">rule change-generated-target-prefix ( type : properties * : prefix )</code>
+ <para>
+ Change the prefix previously registered for this type/properties
+ combination. If prefix is not yet specified, sets it.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.generated-target-prefix">
+ <indexterm zone="bbv2.reference.modules.type.generated-target-prefix">
+ <primary>generated-target-prefix</primary>
+ </indexterm>
+ <code language="jam">rule generated-target-prefix ( type : property-set )</code>
+ <para>
+ Returns the prefix used when generating a file of
+ <code language="jam">type</code> with the given properties.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.modules.type.type">
+ <indexterm zone="bbv2.reference.modules.type.type">
+ <primary>type</primary>
+ <secondary>rule</secondary>
+ </indexterm>
+ <code language="jam">rule type ( filename )</code>
+ <para>
+ 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.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/typed-target.xml b/tools/build/v2/doc/src/typed-target.xml
new file mode 100644
index 0000000000..2a7d7c98c7
--- /dev/null
+++ b/tools/build/v2/doc/src/typed-target.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
+ "http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
+
+<section id="bbv2.reference.class.typed-target">
+
+ <title>Class typed-target</title>
+ <indexterm>
+ <primary>typed-target</primary>
+ </indexterm>
+
+<programlisting language="jam">
+class typed-target : <link linkend="bbv2.reference.class.basic-target">basic-target</link> {
+ rule <link linkend="bbv2.reference.class.typed-target.__init__">__init__</link> ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )
+ rule <link linkend="bbv2.reference.class.typed-target.type">type</link> ( )
+ rule <link linkend="bbv2.reference.class.typed-target.construct">construct</link> ( name : source-targets * : property-set )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.abstract-target">abstract-target</link>
+ rule <link linkend="bbv2.reference.class.abstract-target.name">name</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.project">project</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.location">location</link> ( )
+ rule <link linkend="bbv2.reference.class.abstract-target.full-name">full-name</link> ( )
+
+ # Methods inherited from <link linkend="bbv2.reference.class.basic-target">basic-target</link>
+ rule <link linkend="bbv2.reference.class.basic-target.generate">generate</link> ( property-set )
+ }
+</programlisting>
+
+ <para>
+ <link linkend="bbv2.reference.class.typed-target">typed-target</link>
+ is the most common kind of target alternative. Rules for creating
+ typed targets are defined automatically for each type.
+ </para>
+
+ <orderedlist>
+
+ <listitem id="bbv2.reference.class.typed-target.__init__">
+ <code language="jam">rule __init__ ( name : project : type : sources * : requirements * : default-build * : usage-requirements * )</code>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><literal>name</literal></term>
+ <listitem><para>The name of the target</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>project</literal></term>
+ <listitem>
+ <para>
+ The <link linkend="bbv2.reference.class.project-target">project</link>
+ in which the target is declared.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>type</literal></term>
+ <listitem>
+ <para>
+ The <link linkend="bbv2.reference.modules.type">type</link>
+ of the target.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.typed-target.type">
+ <indexterm zone="bbv2.reference.class.typed-target.type">
+ <primary>type</primary>
+ <secondary>Typed Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule type ( )</code>
+ <para>
+ Returns the <link linkend="bbv2.reference.modules.type">type</link>
+ of the target.
+ </para>
+ </listitem>
+
+ <listitem id="bbv2.reference.class.typed-target.construct">
+ <indexterm zone="bbv2.reference.class.typed-target.construct">
+ <primary>construct</primary>
+ <secondary>Typed Target Method</secondary>
+ </indexterm>
+ <code language="jam">rule construct ( name : source-targets * : property-set )</code>
+ <para>
+ Implements <link linkend="bbv2.reference.class.basic-target.construct">
+ basic-target.construct</link>. Attempts to create a target of
+ the correct type using generators appropriate for the given
+ <link linkend="bbv2.reference.class.property-set">property-set</link>.
+ Returns a <link linkend="bbv2.reference.class.property-set">
+ property-set</link> containing the usage requirements
+ and a list of virtual targets.
+
+ <note>
+ <para>
+ This function is invoked automatically by
+ <link linkend="bbv2.reference.class.basic-target.generate">basic-target.generate</link>
+ and should not be called directly by users.
+ </para>
+ </note>
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+</section>
diff --git a/tools/build/v2/doc/src/userman.xml b/tools/build/v2/doc/src/userman.xml
index c8f6b685f4..c3f070f39a 100644
--- a/tools/build/v2/doc/src/userman.xml
+++ b/tools/build/v2/doc/src/userman.xml
@@ -3,7 +3,7 @@
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude"
- id="bbv2" last-revision="$Date: 2011-01-25 13:06:12 -0500 (Tue, 25 Jan 2011) $">
+ id="bbv2" last-revision="$Date: 2011-01-25 10:06:12 -0800 (Tue, 25 Jan 2011) $">
<partinfo>
<copyright>
<year>2006</year>
diff --git a/tools/build/v2/engine/build.bat b/tools/build/v2/engine/build.bat
index f927b7697c..2982fb9c93 100644
--- a/tools/build/v2/engine/build.bat
+++ b/tools/build/v2/engine/build.bat
@@ -28,7 +28,7 @@ ECHO ### You can specify the toolset as the argument, i.e.:
ECHO ### .\build.bat msvc
ECHO ###
ECHO ### Toolsets supported by this script are: borland, como, gcc, gcc-nocygwin,
-ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10
+ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10, vc11
ECHO ###
call :Set_Error
endlocal
@@ -101,6 +101,16 @@ call :Test_Empty %ProgramFiles%
if not errorlevel 1 set ProgramFiles=C:\Program Files
call :Clear_Error
+if NOT "_%VS110COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET=vc11"
+ set "BOOST_JAM_TOOLSET_ROOT=%VS110COMNTOOLS%..\..\VC\"
+ goto :eof)
+call :Clear_Error
+if EXIST "%ProgramFiles%\Microsoft Visual Studio 11.0\VC\VCVARSALL.BAT" (
+ set "BOOST_JAM_TOOLSET=vc11"
+ set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio 11.0\VC\"
+ goto :eof)
+call :Clear_Error
if NOT "_%VS100COMNTOOLS%_" == "__" (
set "BOOST_JAM_TOOLSET=vc10"
set "BOOST_JAM_TOOLSET_ROOT=%VS100COMNTOOLS%..\..\VC\"
@@ -371,6 +381,21 @@ set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
set "_known_=1"
:Skip_VC10
+if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc11_" goto Skip_VC11
+if NOT "_%VS110COMNTOOLS%_" == "__" (
+ set "BOOST_JAM_TOOLSET_ROOT=%VS110COMNTOOLS%..\..\VC\"
+ )
+if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%VCVARSALL.BAT" %BOOST_JAM_ARGS%
+if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
+ if "_%VCINSTALLDIR%_" == "__" (
+ set "PATH=%BOOST_JAM_TOOLSET_ROOT%bin;%PATH%"
+ ) )
+set "BOOST_JAM_CC=cl /nologo /RTC1 /Zi /MTd /Fobootstrap/ /Fdbootstrap/ -DNT -DYYDEBUG -wd4996 kernel32.lib advapi32.lib user32.lib"
+set "BOOST_JAM_OPT_JAM=/Febootstrap\jam0"
+set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0"
+set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0"
+set "_known_=1"
+:Skip_VC11
if NOT "_%BOOST_JAM_TOOLSET%_" == "_borland_" goto Skip_BORLAND
if "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" (
call :Test_Path bcc32.exe )
@@ -438,9 +463,9 @@ echo ###
set YYACC_SOURCES=yyacc.c
set MKJAMBASE_SOURCES=mkjambase.c
set BJAM_SOURCES=
-set BJAM_SOURCES=%BJAM_SOURCES% command.c compile.c debug.c execnt.c expand.c filent.c glob.c hash.c
+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% newstr.c option.c output.c parse.c pathunix.c regexp.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
@@ -457,10 +482,13 @@ set test=###%test%###
set test=%test:"###=%
set test=%test:###"=%
set test=%test:###=%
-if "%test%" == "--update" set BJAM_UPDATE=update
+if "%test%" == "--update" goto Found_Update
endlocal
shift
if not "_%BJAM_UPDATE%_" == "_update_" goto Check_Update
+:Found_Update
+endlocal
+set BJAM_UPDATE=update
:Check_Update_End
if "_%BJAM_UPDATE%_" == "_update_" (
if not exist ".\bootstrap\jam0.exe" (
@@ -506,9 +534,6 @@ rename y.tab.h jamgram.h
%BOOST_JAM_CC% %BOOST_JAM_OPT_JAM% %BJAM_SOURCES%
:Skip_Bootstrap
@if not exist ".\bootstrap\jam0.exe" goto Skip_Jam
-@if "_%BJAM_UPDATE%_" == "_update_" goto Skip_Clean
-.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " clean
-:Skip_Clean
@set args=%*
@echo OFF
:Set_Args
@@ -526,6 +551,9 @@ set args=%args:~1%
goto Set_Args
:Set_Args_End
@echo ON
+@if "_%BJAM_UPDATE%_" == "_update_" goto Skip_Clean
+.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " %args% clean
+:Skip_Clean
.\bootstrap\jam0 -f build.jam --toolset=%BOOST_JAM_TOOLSET% "--toolset-root=%BOOST_JAM_TOOLSET_ROOT% " %args%
:Skip_Jam
diff --git a/tools/build/v2/engine/build.jam b/tools/build/v2/engine/build.jam
index 266b07a17d..1efc3f1f0b 100644
--- a/tools/build/v2/engine/build.jam
+++ b/tools/build/v2/engine/build.jam
@@ -18,12 +18,9 @@ for local v in ARGV CC CFLAGS LIBS
# Platform related specifics.
if $(OS) = NT { rule .path { return "$(<:J=\\)" ; } ./ = "/" ; }
-else if $(OS) = OS2 { rule .path { return "$(<:J=\\)" ; } ./ = "/" ; }
-else if $(OS) = VMS { rule .path { return "[.$(<:J=/)]" ; } }
-else if $(OS) = MAC { rule .path { return ":$(<:J=\:)" ; } }
else { rule .path { return "$(<:J=/)" ; } }
-if $(OS) = VMS { . = "_" ; }
-else { . = "." ; }
+
+. = "." ;
./ ?= "" ;
# Info about what we are building.
@@ -71,7 +68,7 @@ if $(with-python)
{
--python-include = [ .path $(python-location) include ] ;
--python-lib = ;
- for local v in 26 25 24 23 22
+ for local v in 27 26 25 24 23 22
{
--python-lib ?=
[ GLOB [ .path $(python-location) libs ] : "python$(v).lib" ]
@@ -94,7 +91,7 @@ if $(with-python)
{
--python-include = ;
--python-lib = ;
- for local v in 2.6 2.5 2.4 2.3 2.2
+ for local v in 2.7 2.6 2.5 2.4 2.3 2.2
{
local inc = [ GLOB [ .path $(python-location) include ] : python$(v) ] ;
local lib = [ GLOB [ .path $(python-location) lib ] : libpython$(v)* ] ;
@@ -214,6 +211,7 @@ toolset gcc gcc : "-o " : -D
: -pedantic -fno-strict-aliasing
[ opt --release : [ opt --symbols : -g : -s ] -O3 ]
[ opt --debug : -g -O0 -fno-inline ]
+ [ opt --profile : -O3 -g -pg ]
-I$(--python-include) -I$(--extra-include) -Wno-long-long
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
## GCC 2.x, 3.x on CYGWIN but without cygwin1.dll
@@ -319,14 +317,14 @@ toolset pgi pgcc : "-o " : -D
## Sun Workshop 6 C++
toolset sun cc : "-o " : -D
:
- [ opt --release : -s -fast -xO4 ]
+ [ opt --release : -s -xO3 ]
[ opt --debug : -g ]
-I$(--python-include) -I$(--extra-include)
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
## Sun Workshop 6 C++ (old alias)
toolset sunpro cc : "-o " : -D
:
- [ opt --release : -s -fast -xO4 ]
+ [ opt --release : -s -xO3 ]
[ opt --debug : -g ]
-I$(--python-include) -I$(--extra-include)
: -L$(--python-lib[1]) -l$(--python-lib[2]) ;
@@ -372,18 +370,13 @@ toolset vc10 cl : /Fe /Fe /Fd /Fo : -D
[ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ]
-I$(--python-include) -I$(--extra-include)
: kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ;
-## VMS/OpenVMS DEC C
-toolset vmsdecc cc : /OBJECT= : "/DEFINES=(" "," ")"
- : /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES
- [ opt --release : /OPTIMIZE /NODEBUG ]
- [ opt --debug : /NOOPTIMIZE /DEBUG ]
- ;
-toolset vmsdecc link .link : /EXECUTABLE= :
- : /NOMAP
- [ opt --release : /NODEBUG ]
- [ opt --debug : /DEBUG ]
- ;
-
+toolset vc11 cl : /Fe /Fe /Fd /Fo : -D
+ : /nologo
+ [ opt --release : /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) ] ;
@@ -454,17 +447,7 @@ if $(tool.$(toolset).link.cc)
# Put executables in platform-specific subdirectory.
locate-target = $(LOCATE_TARGET) ;
-if $(OS) = VMS
-{
- locate-target ?= bin$(.)vms ;
- platform = vms ;
-}
-else if $(OS) = MAC
-{
- locate-target ?= bin$(.)$(OS:L)$(OSPLAT:L) ;
- platform = $(OS:L)$(OSPLAT:L) ;
-}
-else if $(OSPLAT)
+if $(OSPLAT)
{
locate-target ?= bin$(.)$(OS:L)$(OSPLAT:L) ;
platform = $(OS:L)$(OSPLAT:L) ;
@@ -492,12 +475,12 @@ if --show-locate-target in $(ARGV)
ECHO $(locate-target) ;
}
-# We have some different files for UNIX, VMS, and NT.
+# We have some different files for UNIX, and NT.
jam.source =
- command.c compile.c debug.c expand.c glob.c
+ 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 newstr.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
@@ -509,18 +492,6 @@ if $(OS) = NT
{
jam.source += execnt.c filent.c pathunix.c ;
}
-else if $(OS) = OS2
-{
- jam.source += execunix.c fileos2.c pathunix.c ;
-}
-else if $(OS) = VMS
-{
- jam.source += execvms.c filevms.c pathvms.c ;
-}
-else if $(OS) = MAC
-{
- jam.source += execmac.c filemac.c pathmac.c ;
-}
else
{
jam.source += execunix.c fileunix.c pathunix.c ;
@@ -565,10 +536,6 @@ if ( $(OS) = NT ) && ! NT in $(--defs)
{
--defs += NT ;
}
-if $(OS) = VMS
-{
- --defs += VMS ;
-}
--defs += YYSTACKSIZE=5000 ;
if $(with-python)
@@ -597,18 +564,12 @@ if $(OS) = NT { actions piecemeal together existing [DELETE] {
if $(UNIX) = true { actions piecemeal together existing [DELETE] {
rm -f "$(>)"
} }
-if $(OS) = VMS { actions piecemeal together existing [DELETE] {
- DELETE $(>[--2]:J=";*, ") $(>[-1]);*
-} }
if $(OS) = NT {
--chmod+w = "attrib -r " ;
}
if $(UNIX) = true {
--chmod+w = "chmod +w " ;
}
-if $(OS) = VMS {
- --chmod+w = "SET FILE/PROT=(S:RWED) " ;
-}
rule .mkdir
{
@@ -622,14 +583,11 @@ if $(OS) = NT { actions [MKDIR] {
if $(UNIX) = true { actions [MKDIR] {
mkdir "$(<)"
} }
-if $(OS) = VMS { actions [MKDIR] {
- CREATE/DIR $(<J=", ")
-} }
rule .exe
{
local exe = $(<) ;
- if $(OS) = NT || ( $(UNIX) = true && $(OS) = CYGWIN ) || $(OS) = VMS { exe = $(exe:S=.exe) ; }
+ if $(OS) = NT || ( $(UNIX) = true && $(OS) = CYGWIN ) { exe = $(exe:S=.exe) ; }
LOCATE on $(exe) = $(locate-target) ;
DEPENDS all : $(exe) ;
.mkdir $(locate-target) ;
@@ -665,18 +623,16 @@ rule .exe
return $(exe) ;
}
if ! $(--def[2]) { actions [COMPILE] {
- "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def)$(--defs)" "$(--flags)" "$(--libs)" "$(>)"
+ "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def)$(--defs)" "$(--flags)" "$(>)" "$(--libs)"
} }
else { actions [COMPILE] {
- "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def[1])$(--defs:J=$(--def[2]))$(--def[3])" "$(--flags)" "$(--libs)" "$(>)"
-} }
-if $(OS) = VMS { actions [COMPILE.LINK] {
- "$(--link)" $(--link-bin)$(<:D=) $(--link-dir)$(<:D)$(./) $(--link-out)$(<) $(--link-def)$(--link-defs) $(--link-flags) "$(--link-libs)" $(>J=", ")
-} }
-else { actions [COMPILE.LINK] {
- "$(--link)" "$(--link-bin)$(<:D=)" "$(--link-dir)$(<:D)$(./)" "$(--link-out)$(<)" "$(--link-def)$(--link-defs)" "$(--link-flags)" "$(--link-libs)" "$(>)"
+ "$(--cc)" "$(--bin)$(<:D=)" "$(--dir)$(<:D)$(./)" $(--out)$(<) "$(--def[1])$(--defs:J=$(--def[2]))$(--def[3])" "$(--flags)" "$(>)" "$(--libs)"
} }
+actions [COMPILE.LINK] {
+ "$(--link)" "$(--link-bin)$(<:D=)" "$(--link-dir)$(<:D)$(./)" "$(--link-out)$(<)" "$(--link-def)$(--link-defs)" "$(--link-flags)" "$(>)" "$(--link-libs)"
+}
+
rule .link
{
DEPENDS all : $(<) ;
@@ -690,9 +646,6 @@ if $(OS) = NT { actions [LINK] {
if $(UNIX) = true { actions [LINK] {
ln -fs "$(>)" "$(<)"
} }
-if $(OS) = VMS { actions [LINK] {
- COPY/REPLACE $(>) $(<)
-} }
rule .copy
{
@@ -720,9 +673,6 @@ if $(OS) = NT { actions [MOVE] {
if $(UNIX) = true { actions [MOVE] {
mv -f "$(>)" "$(<)"
} }
-if $(OS) = VMS { actions [MOVE] {
- RENAME "$(>)" "$(<)"
-} }
# Generate the grammar tokens table, and the real yacc grammar.
rule .yyacc
@@ -796,13 +746,6 @@ if $(UNIX) = true { actions [YACC] {
exit 1
fi
} }
-if $(OS) = VMS { actions [YACC] {
- IF "$(yacc)" $(>)
- THEN
- RENAME y_tab$(<[1]:S) $(<[1])
- RENAME y_tab$(<[2]:S) $(<[2])
- ENDIF
-} }
if $(grammar) && ! $(yacc)
{
EXIT "Could not find the 'yacc' tool, and therefore can not build the grammar." ;
@@ -888,7 +831,7 @@ dist.source =
dist.source = $(dist.source:D=)
$(dist.license[1])
$(dist.docs)
- build.jam build.bat build.sh build_vms.com
+ build.jam build.bat build.sh
Jambase
jamgram.y jamgram.yy
[ .path modules set.c ]
diff --git a/tools/build/v2/engine/build.sh b/tools/build/v2/engine/build.sh
index f1fb806d3c..e3a4498b7a 100755
--- a/tools/build/v2/engine/build.sh
+++ b/tools/build/v2/engine/build.sh
@@ -245,9 +245,9 @@ echo "###"
YYACC_SOURCES="yyacc.c"
MKJAMBASE_SOURCES="mkjambase.c"
BJAM_SOURCES="\
- command.c compile.c debug.c expand.c glob.c hash.c\
+ 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\
- newstr.c option.c output.c parse.c pathunix.c pathvms.c regexp.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\
@@ -297,7 +297,7 @@ if test "${BJAM_UPDATE}" != "update" ; then
fi
if test -x "./bootstrap/jam0" ; then
if test "${BJAM_UPDATE}" != "update" ; then
- echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" clean
+ echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" "$@" clean
fi
echo_run ./bootstrap/jam0 -f build.jam --toolset=$BOOST_JAM_TOOLSET "--toolset-root=$BOOST_JAM_TOOLSET_ROOT" "$@"
fi
diff --git a/tools/build/v2/engine/build_vms.com b/tools/build/v2/engine/build_vms.com
deleted file mode 100644
index 965b634247..0000000000
--- a/tools/build/v2/engine/build_vms.com
+++ /dev/null
@@ -1,105 +0,0 @@
-$ ! Copyright 2002-2003 Rene Rivera, Johan Nilsson.
-$ ! 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)
-$ !
-$ ! bootstrap build script for Jam
-$ !
-$ SAY :== WRITE SYS$OUTPUT
-$ !
-$ ON WARNING THEN CONTINUE
-$ !
-$ IF "" .NES. F$SEARCH("[.bootstrap_vms]*.*")
-$ THEN
-$ SAY "Cleaning previous boostrap files..."
-$ !
-$ SET FILE/PROTECTION=(S:RWED) [.bootstrap_vms]*.*;*
-$ DELETE [.bootstrap_vms]*.*;*
-$ ENDIF
-$ !
-$ IF "" .NES. F$SEARCH("bootstrap_vms.dir")
-$ THEN
-$ SAY "Removing previous boostrap directory..."
-$ !
-$ SET FILE/PROT=(S:RWED) bootstrap_vms.dir
-$ DELETE bootstrap_vms.dir;
-$ ENDIF
-$ !
-$ SAY "Creating boostrap directory..."
-$ !
-$ CREATE/DIR [.bootstrap_vms]
-$ !
-$ SAY "Building bootstrap jam..."
-$ !
-$ CC_FLAGS = "/DEFINE=VMS /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES "
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]builtins.obj builtins.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]command.obj command.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]compile.obj compile.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]execvms.obj execvms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]expand.obj expand.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]filesys.obj filesys.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]filevms.obj filevms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]glob.obj glob.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]hash.obj hash.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]hdrmacro.obj hdrmacro.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]headers.obj headers.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jam.obj jam.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jambase.obj jambase.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]jamgram.obj jamgram.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]lists.obj lists.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]make.obj make.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]make1.obj make1.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]modules.obj modules.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]newstr.obj newstr.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]option.obj option.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]parse.obj parse.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]pathvms.obj pathvms.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]pwd.obj pwd.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]regexp.obj regexp.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]rules.obj rules.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]scan.obj scan.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]search.obj search.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]strings.obj strings.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]subst.obj subst.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]timestamp.obj timestamp.c
-$ cc 'CC_FLAGS /OBJECT=[.bootstrap_vms]variable.obj variable.c
-$ link -
- /EXECUTABLE=[.bootstrap_vms]jam0.exe -
- [.bootstrap_vms]builtins.obj, -
- [.bootstrap_vms]command.obj, -
- [.bootstrap_vms]compile.obj, -
- [.bootstrap_vms]execvms.obj, -
- [.bootstrap_vms]expand.obj, -
- [.bootstrap_vms]filesys.obj, -
- [.bootstrap_vms]filevms.obj, -
- [.bootstrap_vms]glob.obj, -
- [.bootstrap_vms]hash.obj, -
- [.bootstrap_vms]hdrmacro.obj, -
- [.bootstrap_vms]headers.obj, -
- [.bootstrap_vms]jam.obj, -
- [.bootstrap_vms]jambase.obj, -
- [.bootstrap_vms]jamgram.obj, -
- [.bootstrap_vms]lists.obj, -
- [.bootstrap_vms]make.obj, -
- [.bootstrap_vms]make1.obj, -
- [.bootstrap_vms]modules.obj, -
- [.bootstrap_vms]newstr.obj, -
- [.bootstrap_vms]option.obj, -
- [.bootstrap_vms]parse.obj, -
- [.bootstrap_vms]pathvms.obj, -
- [.bootstrap_vms]pwd.obj, -
- [.bootstrap_vms]regexp.obj, -
- [.bootstrap_vms]rules.obj, -
- [.bootstrap_vms]scan.obj, -
- [.bootstrap_vms]search.obj, -
- [.bootstrap_vms]strings.obj, -
- [.bootstrap_vms]subst.obj, -
- [.bootstrap_vms]timestamp.obj, -
- [.bootstrap_vms]variable.obj
-$ !
-$ SAY "Cleaning any previous build..."
-$ !
-$ MCR [.bootstrap_vms]jam0.exe -f build.jam --toolset=vmsdecc clean
-$ !
-$ SAY "Building Boost.Jam..."
-$ !
-$ MCR [.bootstrap_vms]jam0.exe -f build.jam --toolset=vmsdecc
diff --git a/tools/build/v2/engine/builtins.c b/tools/build/v2/engine/builtins.c
index b28a484ec4..07eaa1534a 100644
--- a/tools/build/v2/engine/builtins.c
+++ b/tools/build/v2/engine/builtins.c
@@ -11,7 +11,7 @@
#include "builtins.h"
#include "rules.h"
#include "filesys.h"
-#include "newstr.h"
+#include "object.h"
#include "regexp.h"
#include "frames.h"
#include "hash.h"
@@ -25,6 +25,7 @@
#include "variable.h"
#include "timestamp.h"
#include "md5.h"
+#include "constants.h"
#include <ctype.h>
#if defined(USE_EXECUNIX)
@@ -65,38 +66,44 @@
*/
#define P0 (PARSE *)0
-#define C0 (char *)0
+#define C0 (OBJECT *)0
#if defined( OS_NT ) || defined( OS_CYGWIN )
- LIST * builtin_system_registry ( PARSE *, FRAME * );
- LIST * builtin_system_registry_names( PARSE *, FRAME * );
+ LIST * builtin_system_registry ( FRAME *, int );
+ LIST * builtin_system_registry_names( FRAME *, int );
#endif
-int glob( char * s, char * c );
+int glob( const char * s, const char * c );
void backtrace ( FRAME * );
void backtrace_line ( FRAME * );
-void print_source_line( PARSE * );
+void print_source_line( FRAME * );
-RULE * bind_builtin( char * name, LIST * (* f)( PARSE *, FRAME * ), int flags, char * * args )
+RULE * bind_builtin( const char * name_, LIST * (* f)( FRAME *, int flags ), int flags, const char * * args )
{
- argument_list* arg_list = 0;
+ FUNCTION * func;
+ RULE * result;
+ OBJECT * name = object_new( name_ );
- if ( args )
- {
- arg_list = args_new();
- lol_build( arg_list->data, args );
- }
+ func = function_builtin( f, flags, args );
+
+ result = new_rule_body( root_module(), name, func, 1 );
+
+ function_free( func );
+
+ object_free( name );
- return new_rule_body( root_module(), name, arg_list,
- parse_make( f, P0, P0, P0, C0, C0, flags ), 1 );
+ return result;
}
-RULE * duplicate_rule( char * name, RULE * other )
+RULE * duplicate_rule( const char * name_, RULE * other )
{
- return import_rule( other, root_module(), name );
+ OBJECT * name = object_new( name_ );
+ RULE * result = import_rule( other, root_module(), name );
+ object_free( name );
+ return result;
}
@@ -116,7 +123,7 @@ void load_builtins()
builtin_echo, 0, 0 ) ) );
{
- char * args[] = { "message", "*", ":", "result-value", "?", 0 };
+ const char * args[] = { "message", "*", ":", "result-value", "?", 0 };
duplicate_rule( "exit",
duplicate_rule( "Exit",
bind_builtin( "EXIT",
@@ -124,13 +131,13 @@ void load_builtins()
}
{
- char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
+ const char * args[] = { "directories", "*", ":", "patterns", "*", ":", "case-insensitive", "?", 0 };
duplicate_rule( "Glob",
bind_builtin( "GLOB", builtin_glob, 0, args ) );
}
{
- char * args[] = { "patterns", "*", 0 };
+ const char * args[] = { "patterns", "*", 0 };
bind_builtin( "GLOB-RECURSIVELY",
builtin_glob_recursive, 0, args );
}
@@ -140,7 +147,7 @@ void load_builtins()
builtin_depends, 1, 0 ) );
{
- char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
+ const char * args[] = { "targets", "*", ":", "targets-to-rebuild", "*", 0 };
bind_builtin( "REBUILDS",
builtin_rebuilds, 0, args );
}
@@ -154,7 +161,7 @@ void load_builtins()
builtin_match, 0, 0 ) );
{
- char * args[] = { "string", ":", "delimiters" };
+ const char * args[] = { "string", ":", "delimiters" };
bind_builtin( "SPLIT_BY_CHARACTERS",
builtin_split_by_characters, 0, 0 );
}
@@ -194,13 +201,13 @@ void load_builtins()
builtin_flags, T_FLAG_RMOLD, 0 );
{
- char * args[] = { "targets", "*", 0 };
+ const char * args[] = { "targets", "*", 0 };
bind_builtin( "UPDATE",
builtin_update, 0, args );
}
{
- char * args[] = { "targets", "*",
+ const char * args[] = { "targets", "*",
":", "log", "?",
":", "ignore-minus-n", "?",
":", "ignore-minus-q", "?", 0 };
@@ -209,33 +216,33 @@ void load_builtins()
}
{
- char * args[] = { "string", "pattern", "replacements", "+", 0 };
+ const char * args[] = { "string", "pattern", "replacements", "+", 0 };
duplicate_rule( "subst",
bind_builtin( "SUBST",
builtin_subst, 0, args ) );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "RULENAMES",
builtin_rulenames, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "VARNAMES",
builtin_varnames, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "DELETE_MODULE",
builtin_delete_module, 0, args );
}
{
- char * args[] = { "source_module", "?",
+ const char * args[] = { "source_module", "?",
":", "source_rules", "*",
":", "target_module", "?",
":", "target_rules", "*",
@@ -245,104 +252,98 @@ void load_builtins()
}
{
- char * args[] = { "module", "?", ":", "rules", "*", 0 };
+ const char * args[] = { "module", "?", ":", "rules", "*", 0 };
bind_builtin( "EXPORT",
builtin_export, 0, args );
}
{
- char * args[] = { "levels", "?", 0 };
+ const char * args[] = { "levels", "?", 0 };
bind_builtin( "CALLER_MODULE",
builtin_caller_module, 0, args );
}
{
- char * args[] = { "levels", "?", 0 };
+ const char * args[] = { "levels", "?", 0 };
bind_builtin( "BACKTRACE",
builtin_backtrace, 0, args );
}
{
- char * args[] = { 0 };
+ const char * args[] = { 0 };
bind_builtin( "PWD",
builtin_pwd, 0, args );
}
{
- char * args[] = { "target", "*", ":", "path", "*", 0 };
- bind_builtin( "SEARCH_FOR_TARGET",
- builtin_search_for_target, 0, args );
- }
-
- {
- char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
+ const char * args[] = { "modules_to_import", "+", ":", "target_module", "?", 0 };
bind_builtin( "IMPORT_MODULE",
builtin_import_module, 0, args );
}
{
- char * args[] = { "module", "?", 0 };
+ const char * args[] = { "module", "?", 0 };
bind_builtin( "IMPORTED_MODULES",
builtin_imported_modules, 0, args );
}
{
- char * args[] = { "instance_module", ":", "class_module", 0 };
+ const char * args[] = { "instance_module", ":", "class_module", 0 };
bind_builtin( "INSTANCE",
builtin_instance, 0, args );
}
{
- char * args[] = { "sequence", "*", 0 };
+ const char * args[] = { "sequence", "*", 0 };
bind_builtin( "SORT",
builtin_sort, 0, args );
}
{
- char * args[] = { "path_parts", "*", 0 };
+ const char * args[] = { "path_parts", "*", 0 };
bind_builtin( "NORMALIZE_PATH",
builtin_normalize_path, 0, args );
}
{
- char * args[] = { "args", "*", 0 };
+ const char * args[] = { "args", "*", 0 };
bind_builtin( "CALC",
builtin_calc, 0, args );
}
{
- char * args[] = { "module", ":", "rule", 0 };
+ const char * args[] = { "module", ":", "rule", 0 };
bind_builtin( "NATIVE_RULE",
builtin_native_rule, 0, args );
}
{
- char * args[] = { "module", ":", "rule", ":", "version", 0 };
+ const char * args[] = { "module", ":", "rule", ":", "version", 0 };
bind_builtin( "HAS_NATIVE_RULE",
builtin_has_native_rule, 0, args );
}
{
- char * args[] = { "module", "*", 0 };
+ const char * args[] = { "module", "*", 0 };
bind_builtin( "USER_MODULE",
builtin_user_module, 0, args );
}
{
- char * args[] = { 0 };
+ const char * args[] = { 0 };
bind_builtin( "NEAREST_USER_LOCATION",
builtin_nearest_user_location, 0, args );
}
{
- char * args[] = { "file", 0 };
+ const char * args[] = { "file", 0 };
bind_builtin( "CHECK_IF_FILE",
builtin_check_if_file, 0, args );
}
#ifdef HAVE_PYTHON
{
- char * args[] = { "python-module", ":", "function", ":",
+ const char * args[] = { "python-module", ":", "function", ":",
"jam-module", ":", "rule-name", 0 };
bind_builtin( "PYTHON_IMPORT_RULE",
builtin_python_import_rule, 0, args );
@@ -351,56 +352,56 @@ void load_builtins()
# if defined( OS_NT ) || defined( OS_CYGWIN )
{
- char * args[] = { "key_path", ":", "data", "?", 0 };
+ const char * args[] = { "key_path", ":", "data", "?", 0 };
bind_builtin( "W32_GETREG",
builtin_system_registry, 0, args );
}
{
- char * args[] = { "key_path", ":", "result-type", 0 };
+ const char * args[] = { "key_path", ":", "result-type", 0 };
bind_builtin( "W32_GETREGNAMES",
builtin_system_registry_names, 0, args );
}
# endif
{
- char * args[] = { "command", ":", "*", 0 };
+ const char * args[] = { "command", ":", "*", 0 };
duplicate_rule( "SHELL",
bind_builtin( "COMMAND",
builtin_shell, 0, args ) );
}
{
- char * args[] = { "string", 0 };
+ const char * args[] = { "string", 0 };
bind_builtin( "MD5",
builtin_md5, 0, args ) ;
}
{
- char * args[] = { "name", ":", "mode", 0 };
+ const char * args[] = { "name", ":", "mode", 0 };
bind_builtin( "FILE_OPEN",
builtin_file_open, 0, args );
}
{
- char * args[] = { "string", ":", "width", 0 };
+ const char * args[] = { "string", ":", "width", 0 };
bind_builtin( "PAD",
builtin_pad, 0, args );
}
{
- char * args[] = { "targets", "*", 0 };
+ const char * args[] = { "targets", "*", 0 };
bind_builtin( "PRECIOUS",
builtin_precious, 0, args );
}
{
- char * args [] = { 0 };
+ const char * args [] = { 0 };
bind_builtin( "SELF_PATH", builtin_self_path, 0, args );
}
{
- char * args [] = { "path", 0 };
+ const char * args [] = { "path", 0 };
bind_builtin( "MAKEDIR", builtin_makedir, 0, args );
}
@@ -420,11 +421,11 @@ void load_builtins()
* The CALC rule performs simple mathematical operations on two arguments.
*/
-LIST * builtin_calc( PARSE * parse, FRAME * frame )
+LIST * builtin_calc( FRAME * frame, int flags )
{
LIST * arg = lol_get( frame->args, 0 );
- LIST * result = 0;
+ LIST * result = L0;
long lhs_value;
long rhs_value;
long result_value;
@@ -432,17 +433,18 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
char const * lhs;
char const * op;
char const * rhs;
+ LISTITER iter = list_begin( arg ), end = list_end( arg );
- if ( arg == 0 ) return L0;
- lhs = arg->string;
+ if ( iter == end ) return L0;
+ lhs = object_str( list_item( iter ) );
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- op = arg->string;
+ iter = list_next( iter );
+ if ( iter == end ) return L0;
+ op = object_str( list_item( iter ) );
- arg = list_next( arg );
- if ( arg == 0 ) return L0;
- rhs = arg->string;
+ iter = list_next( iter );
+ if ( iter == end ) return L0;
+ rhs = object_str( list_item( iter ) );
lhs_value = atoi( lhs );
rhs_value = atoi( rhs );
@@ -461,7 +463,7 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
}
sprintf( buffer, "%ld", result_value );
- result = list_new( result, newstr( buffer ) );
+ result = list_push_back( result, object_new( buffer ) );
return result;
}
@@ -474,21 +476,22 @@ LIST * builtin_calc( PARSE * parse, FRAME * frame )
* targets and sources as TARGETs.
*/
-LIST * builtin_depends( PARSE * parse, FRAME * frame )
+LIST * builtin_depends( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * sources = lol_get( frame->args, 1 );
- LIST * l;
-
- for ( l = targets; l; l = list_next( l ) )
+ LISTITER iter, end;
+
+ iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ 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. */
- if ( parse->num )
+ if ( flags )
{
if ( !t->includes )
{
@@ -502,9 +505,10 @@ LIST * builtin_depends( PARSE * parse, FRAME * frame )
}
/* Enter reverse links */
- for ( l = sources; l; l = list_next( l ) )
+ iter = list_begin( sources ), end = list_end( sources );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * s = bindtarget( l->string );
+ TARGET * s = bindtarget( list_item( iter ) );
s->dependants = targetlist( s->dependants, targets );
}
@@ -520,15 +524,15 @@ LIST * builtin_depends( PARSE * parse, FRAME * frame )
* argument.
*/
-LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
+LIST * builtin_rebuilds( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * rebuilds = lol_get( frame->args, 1 );
- LIST * l;
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
- for ( l = targets; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
t->rebuilds = targetlist( t->rebuilds, rebuilds );
}
@@ -543,7 +547,7 @@ LIST * builtin_rebuilds( PARSE * parse, FRAME * frame )
* taken.
*/
-LIST * builtin_echo( PARSE * parse, FRAME * frame )
+LIST * builtin_echo( FRAME * frame, int flags )
{
list_print( lol_get( frame->args, 0 ) );
printf( "\n" );
@@ -559,13 +563,14 @@ LIST * builtin_echo( PARSE * parse, FRAME * frame )
* with a failure status.
*/
-LIST * builtin_exit( PARSE * parse, FRAME * frame )
+LIST * builtin_exit( FRAME * frame, int flags )
{
+ LIST * code = lol_get( frame->args, 1 );
list_print( lol_get( frame->args, 0 ) );
printf( "\n" );
- if ( lol_get( frame->args, 1 ) )
+ if ( !list_empty( code ) )
{
- exit( atoi( lol_get( frame->args, 1 )->string ) );
+ exit( atoi( object_str( list_front( code ) ) ) );
}
else
{
@@ -582,11 +587,12 @@ LIST * builtin_exit( PARSE * parse, FRAME * frame )
* It binds each target as a TARGET.
*/
-LIST * builtin_flags( PARSE * parse, FRAME * frame )
+LIST * builtin_flags( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = list_next( l ) )
- bindtarget( l->string )->flags |= parse->num;
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ bindtarget( list_item( iter ) )->flags |= flags;
return L0;
}
@@ -612,10 +618,10 @@ static void downcase_inplace( char * p )
static void builtin_glob_back
(
- void * closure,
- char * file,
- int status,
- time_t time
+ void * closure,
+ OBJECT * file,
+ int status,
+ time_t time
)
{
PROFILE_ENTER( BUILTIN_GLOB_BACK );
@@ -624,15 +630,16 @@ static void builtin_glob_back
LIST * l;
PATHNAME f;
string buf[ 1 ];
+ LISTITER iter, end;
/* Null out directory for matching. We wish we had file_dirscan() pass up a
* PATHNAME.
*/
- path_parse( file, &f );
+ path_parse( object_str( file ), &f );
f.f_dir.len = 0;
/* For globbing, we unconditionally ignore current and parent directory
- * items. Since they items always exist, there is no reason why caller of
+ * items. Since these items always exist, there is no reason why caller of
* GLOB would want to see them. We could also change file_dirscan(), but
* then paths with embedded "." and ".." would not work anywhere.
*/
@@ -648,11 +655,12 @@ static void builtin_glob_back
if ( globbing->case_insensitive )
downcase_inplace( buf->value );
- for ( l = globbing->patterns; l; l = l->next )
+ iter = list_begin( globbing->patterns ), end = list_end( globbing->patterns );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- if ( !glob( l->string, buf->value ) )
+ if ( !glob( object_str( list_item( iter ) ), buf->value ) )
{
- globbing->results = list_new( globbing->results, newstr( file ) );
+ globbing->results = list_push_back( globbing->results, object_copy( file ) );
break;
}
}
@@ -665,17 +673,18 @@ static void builtin_glob_back
static LIST * downcase_list( LIST * in )
{
- LIST * result = 0;
+ LIST * result = L0;
+ LISTITER iter = list_begin( in ), end = list_end( in );
string s[ 1 ];
string_new( s );
- while ( in )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- string_copy( s, in->string );
+ string_append( s, object_str( list_item( iter ) ) );
downcase_inplace( s->value );
- result = list_append( result, list_new( 0, newstr( s->value ) ) );
- in = in->next;
+ result = list_push_back( result, object_new( s->value ) );
+ string_truncate( s, 0 );
}
string_free( s );
@@ -683,11 +692,12 @@ static LIST * downcase_list( LIST * in )
}
-LIST * builtin_glob( PARSE * parse, FRAME * frame )
+LIST * builtin_glob( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
LIST * r = lol_get( frame->args, 1 );
+ LISTITER iter, end;
struct globbing globbing;
globbing.results = L0;
@@ -703,8 +713,9 @@ LIST * builtin_glob( PARSE * parse, FRAME * frame )
if ( globbing.case_insensitive )
globbing.patterns = downcase_list( r );
- for ( ; l; l = list_next( l ) )
- file_dirscan( l->string, builtin_glob_back, &globbing );
+ iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ file_dirscan( list_item( iter ), builtin_glob_back, &globbing );
if ( globbing.case_insensitive )
list_free( globbing.patterns );
@@ -724,19 +735,19 @@ static int has_wildcards( char const * str )
* If 'file' exists, append 'file' to 'list'. Returns 'list'.
*/
-static LIST * append_if_exists( LIST * list, char * file )
+static LIST * append_if_exists( LIST * list, OBJECT * file )
{
time_t time;
timestamp( file, &time );
return time > 0
- ? list_new( list, newstr( file ) )
+ ? list_push_back( list, object_copy( file ) )
: list;
}
-LIST * glob1( char * dirname, char * pattern )
+LIST * glob1( OBJECT * dirname, OBJECT * pattern )
{
- LIST * plist = list_new( L0, pattern );
+ LIST * plist = list_new( object_copy(pattern) );
struct globbing globbing;
globbing.results = L0;
@@ -763,7 +774,7 @@ LIST * glob1( char * dirname, char * pattern )
}
-LIST * glob_recursive( char * pattern )
+LIST * glob_recursive( const char * pattern )
{
LIST * result = L0;
@@ -771,7 +782,9 @@ LIST * glob_recursive( char * pattern )
if ( !has_wildcards( pattern ) )
{
/* No metacharacters. Check if the path exists. */
- result = append_if_exists(result, pattern);
+ OBJECT * p = object_new( pattern );
+ result = append_if_exists( result, p );
+ object_free( p );
}
else
{
@@ -798,27 +811,35 @@ LIST * glob_recursive( char * pattern )
dirs = has_wildcards( dirname->value )
? glob_recursive( dirname->value )
- : list_new( dirs, dirname->value );
+ : list_push_back( dirs, object_new( dirname->value ) );
if ( has_wildcards( basename->value ) )
{
- for ( ; dirs; dirs = dirs->next )
- result = list_append( result, glob1( dirs->string,
- basename->value ) );
+ OBJECT * b = object_new( basename->value );
+ LISTITER iter = list_begin( dirs ), end = list_end( dirs );
+ for ( ; iter != end; iter = list_next( iter ) )
+ result = list_append( result, glob1( list_item( iter ), b ) );
+ object_free( b );
}
else
{
+ LISTITER iter = list_begin( dirs ), end = list_end( dirs );
string file_string[ 1 ];
string_new( file_string );
/* No wildcard in basename. */
- for ( ; dirs; dirs = dirs->next )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- path->f_dir.ptr = dirs->string;
- path->f_dir.len = strlen( dirs->string );
+ 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 );
- result = append_if_exists( result, file_string->value );
+ p = object_new( file_string->value );
+
+ result = append_if_exists( result, p );
+
+ object_free( p );
string_truncate( file_string, 0 );
}
@@ -828,11 +849,15 @@ LIST * glob_recursive( char * pattern )
string_free( dirname );
string_free( basename );
+
+ list_free( dirs );
}
else
{
/** No directory, just a pattern. */
- result = list_append( result, glob1( ".", pattern ) );
+ OBJECT * p = object_new( pattern );
+ result = list_append( result, glob1( constant_dot, p ) );
+ object_free( p );
}
}
@@ -840,12 +865,13 @@ LIST * glob_recursive( char * pattern )
}
-LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
+LIST * builtin_glob_recursive( FRAME * frame, int flags )
{
LIST * result = L0;
LIST * l = lol_get( frame->args, 0 );
- for ( ; l; l = l->next )
- result = list_append( result, glob_recursive( l->string ) );
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ result = list_append( result, glob_recursive( object_str( list_item( iter ) ) ) );
return result;
}
@@ -854,26 +880,31 @@ LIST * builtin_glob_recursive( PARSE * parse, FRAME * frame )
* builtin_match() - MATCH rule, regexp matching.
*/
-LIST * builtin_match( PARSE * parse, FRAME * frame )
+LIST * builtin_match( FRAME * frame, int flags )
{
LIST * l;
LIST * r;
- LIST * result = 0;
+ LIST * result = L0;
+ LISTITER l_iter, l_end, r_iter, r_end;
string buf[ 1 ];
string_new( buf );
/* For each pattern */
- for ( l = lol_get( frame->args, 0 ); l; l = l->next )
+ 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 ) )
{
/* Result is cached and intentionally never freed. */
- regexp * re = regex_compile( l->string );
+ regexp * re = regex_compile( list_item( l_iter ) );
/* For each string to match against. */
- for ( r = lol_get( frame->args, 1 ); r; r = r->next )
+ r = lol_get( frame->args, 1 );
+ r_iter = list_begin( r ), r_end = list_end( r );
+ for ( ; r_iter != r_end; r_iter = list_next( r_iter ) )
{
- if ( regexec( re, r->string ) )
+ if ( regexec( re, object_str( list_item( r_iter ) ) ) )
{
int i;
int top;
@@ -889,7 +920,7 @@ LIST * builtin_match( PARSE * parse, FRAME * frame )
for ( i = 1; i <= top; ++i )
{
string_append_range( buf, re->startp[ i ], re->endp[ i ] );
- result = list_new( result, newstr( buf->value ) );
+ result = list_push_back( result, object_new( buf->value ) );
string_truncate( buf, 0 );
}
}
@@ -900,41 +931,45 @@ LIST * builtin_match( PARSE * parse, FRAME * frame )
return result;
}
-LIST * builtin_split_by_characters( PARSE * parse, FRAME * frame )
+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 = 0;
+ LIST * result = L0;
+
+ string buf[ 1 ];
- char* s = strdup (l1->string);
- char* delimiters = l2->string;
- char* t;
+ const char * delimiters = object_str( list_front( l2 ) );
+ char * t;
- t = strtok (s, delimiters);
- while (t)
+ string_copy( buf, object_str( list_front( l1 ) ) );
+
+ t = strtok( buf->value, delimiters) ;
+ while ( t )
{
- result = list_new(result, newstr(t));
- t = strtok (NULL, delimiters);
+ result = list_push_back( result, object_new( t ) );
+ t = strtok( NULL, delimiters );
}
- free (s);
+ string_free( buf );
return result;
}
-LIST * builtin_hdrmacro( PARSE * parse, FRAME * frame )
+LIST * builtin_hdrmacro( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for ( ; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* Scan file for header filename macro definitions. */
if ( DEBUG_HEADER )
printf( "scanning '%s' for header file macro definitions\n",
- l->string );
+ object_str( list_item( iter ) ) );
macro_headers( t );
}
@@ -955,15 +990,15 @@ static void add_rule_name( void * r_, void * result_ )
RULE * r = (RULE *)r_;
LIST * * result = (LIST * *)result_;
if ( r->exported )
- *result = list_new( *result, copystr( r->name ) );
+ *result = list_push_back( *result, object_copy( r->name ) );
}
-LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
+LIST * builtin_rulenames( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 );
if ( source_module->rules )
hashenumerate( source_module->rules, add_rule_name, &result );
@@ -984,36 +1019,17 @@ LIST * builtin_rulenames( PARSE * parse, FRAME * frame )
static void add_hash_key( void * np, void * result_ )
{
LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *(char * *)np ) );
+ *result = list_push_back( *result, object_copy( *(OBJECT * *)np ) );
}
-static struct hash * get_running_module_vars()
-{
- struct hash * dummy;
- struct hash * vars = NULL;
- /* Get the global variables pointer (that of the currently running module).
- */
- var_hash_swap( &vars );
- dummy = vars;
- /* Put the global variables pointer in its right place. */
- var_hash_swap( &dummy );
- return vars;
-}
-
-
-LIST * builtin_varnames( PARSE * parse, FRAME * frame )
+LIST * builtin_varnames( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
- /* The running module _always_ has its 'variables' member set to NULL due to
- * the way enter_module() and var_hash_swap() work.
- */
- struct hash * vars = source_module == frame->module
- ? get_running_module_vars()
- : source_module->variables;
+ struct hash * vars = source_module->variables;
if ( vars )
hashenumerate( vars, add_hash_key, &result );
@@ -1027,20 +1043,28 @@ LIST * builtin_varnames( PARSE * parse, FRAME * frame )
* Clears all rules and variables from the given module.
*/
-LIST * builtin_delete_module( PARSE * parse, FRAME * frame )
+LIST * builtin_delete_module( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
LIST * result = L0;
- module_t * source_module = bindmodule( arg0 ? arg0->string : 0 );
+ module_t * source_module = bindmodule( !list_empty(arg0) ? list_front(arg0) : 0 );
delete_module( source_module );
return result;
}
-static void unknown_rule( FRAME * frame, char * key, char * module_name, char * rule_name )
+static void unknown_rule( FRAME * frame, const char * key, module_t * module, OBJECT * rule_name )
{
+ const char * module_name = module->name ? object_str( module->name ) : "";
backtrace_line( frame->prev );
- printf( "%s error: rule \"%s\" unknown in module \"%s\"\n", key, rule_name, module_name );
+ if ( module->name )
+ {
+ printf( "%s error: rule \"%s\" unknown in module \"%s.\"\n", key, object_str( rule_name ), object_str( module->name ) );
+ }
+ else
+ {
+ printf( "%s error: rule \"%s\" unknown in module \"\"\n", key, object_str( rule_name ) );
+ }
backtrace( frame->prev );
exit( 1 );
}
@@ -1067,7 +1091,7 @@ static void unknown_rule( FRAME * frame, char * key, char * module_name, char *
* variables.
*/
-LIST * builtin_import( PARSE * parse, FRAME * frame )
+LIST * builtin_import( FRAME * frame, int flags )
{
LIST * source_module_list = lol_get( frame->args, 0 );
LIST * source_rules = lol_get( frame->args, 1 );
@@ -1076,37 +1100,35 @@ LIST * builtin_import( PARSE * parse, FRAME * frame )
LIST * localize = lol_get( frame->args, 4 );
module_t * target_module =
- bindmodule( target_module_list ? target_module_list->string : 0 );
+ bindmodule( !list_empty( target_module_list ) ? list_front( target_module_list ) : 0 );
module_t * source_module =
- bindmodule( source_module_list ? source_module_list->string : 0 );
+ bindmodule( !list_empty( source_module_list ) ? list_front( source_module_list ) : 0 );
- LIST * source_name;
- LIST * target_name;
+ 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 );
- for ( source_name = source_rules, target_name = target_rules;
- source_name && target_name;
- source_name = list_next( source_name ),
- target_name = list_next( target_name ) )
+ for ( ;
+ source_iter != source_end && target_iter != target_end;
+ source_iter = list_next( source_iter ),
+ target_iter = list_next( target_iter ) )
{
- RULE r_;
- RULE * r = &r_;
+ RULE * r;
RULE * imported;
- r_.name = source_name->string;
if ( !source_module->rules ||
- !hashcheck( source_module->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "IMPORT", source_module->name, r_.name );
+ !(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, target_name->string );
- if ( localize )
- imported->module = target_module;
+ imported = import_rule( r, target_module, list_item( target_iter ) );
+ if ( !list_empty( localize ) )
+ rule_localize( imported, target_module );
/* This rule is really part of some other module. Just refer to it here,
* but do not let it out.
*/
imported->exported = 0;
}
- if ( source_name || target_name )
+ 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" );
@@ -1131,20 +1153,19 @@ LIST * builtin_import( PARSE * parse, FRAME * frame )
* is issued.
*/
-LIST * builtin_export( PARSE * parse, FRAME * frame )
+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( module_list ? module_list->string : 0 );
+ module_t * m = bindmodule( !list_empty( module_list ) ? list_front( module_list ) : 0 );
- for ( ; rules; rules = list_next( rules ) )
+ LISTITER iter = list_begin( rules ), end = list_end( rules );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- RULE r_;
- RULE * r = &r_;
- r_.name = rules->string;
+ RULE * r;
- if ( !m->rules || !hashcheck( m->rules, (HASHDATA * *)&r ) )
- unknown_rule( frame, "EXPORT", m->name, r_.name );
+ if ( !m->rules || !(r = (RULE *)hash_find( m->rules, list_item( iter ) ) ) )
+ unknown_rule( frame, "EXPORT", m, list_item( iter ) );
r->exported = 1;
}
@@ -1157,12 +1178,12 @@ LIST * builtin_export( PARSE * parse, FRAME * frame )
* indicated for a given procedure in debug output or an error backtrace.
*/
-static void get_source_line( PARSE * procedure, char * * file, int * line )
+static void get_source_line( FRAME * frame, const char * * file, int * line )
{
- if ( procedure )
+ if ( frame->file )
{
- char * f = procedure->file;
- int l = procedure->line;
+ const char * f = object_str( frame->file );
+ int l = frame->line;
if ( !strcmp( f, "+" ) )
{
f = "jambase.c";
@@ -1179,12 +1200,12 @@ static void get_source_line( PARSE * procedure, char * * file, int * line )
}
-void print_source_line( PARSE * p )
+void print_source_line( FRAME * frame )
{
- char * file;
+ const char * file;
int line;
- get_source_line( p, &file, &line );
+ get_source_line( frame, &file, &line );
if ( line < 0 )
printf( "(builtin):" );
else
@@ -1205,7 +1226,7 @@ void backtrace_line( FRAME * frame )
}
else
{
- print_source_line( frame->procedure );
+ print_source_line( frame );
printf( " in %s\n", frame->rulename );
}
}
@@ -1231,23 +1252,31 @@ void backtrace( FRAME * frame )
* period.
*/
-LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
+LIST * builtin_backtrace( FRAME * frame, int flags )
{
LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : ( (unsigned int)(-1) >> 1 ) ;
+ int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : (int)( (unsigned int)(-1) >> 1 ) ;
LIST * result = L0;
for ( ; ( frame = frame->prev ) && levels ; --levels )
{
- char * file;
+ const char * file;
int line;
char buf[32];
- get_source_line( frame->procedure, &file, &line );
+ string module_name[1];
+ get_source_line( frame, &file, &line );
sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
- result = list_new( result, newstr( frame->module->name ) );
- result = list_new( result, newstr( frame->rulename ) );
+ string_new( module_name );
+ if ( frame->module->name )
+ {
+ string_append( module_name, object_str( frame->module->name ) );
+ string_append( module_name, "." );
+ }
+ result = list_push_back( result, object_new( file ) );
+ result = list_push_back( result, object_new( buf ) );
+ result = list_push_back( result, object_new( module_name->value ) );
+ result = list_push_back( result, object_new( frame->rulename ) );
+ string_free( module_name );
}
return result;
}
@@ -1265,10 +1294,10 @@ LIST * builtin_backtrace( PARSE * parse, FRAME * frame )
* behavior.
*/
-LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
+LIST * builtin_caller_module( FRAME * frame, int flags )
{
LIST * levels_arg = lol_get( frame->args, 0 );
- int levels = levels_arg ? atoi( levels_arg->string ) : 0 ;
+ int levels = !list_empty( levels_arg ) ? atoi( object_str( list_front( levels_arg ) ) ) : 0 ;
int i;
for ( i = 0; ( i < levels + 2 ) && frame->prev; ++i )
@@ -1276,16 +1305,8 @@ LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
if ( frame->module == root_module() )
return L0;
-
- {
- LIST * result;
- string name;
- string_copy( &name, frame->module->name );
- string_pop_back( &name );
- result = list_new( L0, newstr(name.value) );
- string_free( &name );
- return result;
- }
+ else
+ return list_new( object_copy( frame->module->name ) );
}
@@ -1295,7 +1316,7 @@ LIST * builtin_caller_module( PARSE * parse, FRAME * frame )
* Usage: pwd = [ PWD ] ;
*/
-LIST * builtin_pwd( PARSE * parse, FRAME * frame )
+LIST * builtin_pwd( FRAME * frame, int flags )
{
return pwd();
}
@@ -1305,13 +1326,14 @@ LIST * builtin_pwd( PARSE * parse, FRAME * frame )
* Adds targets to the list of target that jam will attempt to update.
*/
-LIST * builtin_update( PARSE * parse, FRAME * frame )
+LIST * builtin_update( FRAME * frame, int flags )
{
- LIST * result = list_copy( L0, targets_to_update() );
+ LIST * result = list_copy( targets_to_update() );
LIST * arg1 = lol_get( frame->args, 0 );
+ LISTITER iter = list_begin( arg1 ), end = list_end( arg1 );
clear_targets_to_update();
- for ( ; arg1; arg1 = list_next( arg1 ) )
- mark_target_for_updating( newstr( arg1->string ) );
+ for ( ; iter != end; iter = list_next( iter ) )
+ mark_target_for_updating( object_copy( list_item( iter ) ) );
return result;
}
@@ -1325,34 +1347,30 @@ int last_update_now_status;
Third parameter, if non-empty, specifies that the -n option should have
no effect -- that is, all out-of-date targets should be rebuild.
*/
-LIST * builtin_update_now( PARSE * parse, FRAME * frame )
+LIST * builtin_update_now( FRAME * frame, int flags )
{
LIST * targets = lol_get( frame->args, 0 );
LIST * log = lol_get( frame->args, 1 );
- LIST * force = lol_get (frame->args, 2);
- LIST * continue_ = lol_get(frame->args, 3);
- int status = 0;
- int original_stdout;
- int original_stderr;
- int n;
- int targets_count;
- const char** targets2;
- int i;
- int original_noexec;
- int original_quitquick;
+ LIST * force = lol_get( frame->args, 2 );
+ LIST * continue_ = lol_get( frame->args, 3 );
+ int status;
+ int original_stdout = 0;
+ int original_stderr = 0;
+ int original_noexec = 0;
+ int original_quitquick = 0;
- if (log)
+ if ( !list_empty( log ) )
{
- int fd = atoi(log->string);
+ int fd = atoi( object_str( list_front( log ) ) );
/* Redirect stdout and stderr, temporary, to the log file. */
- original_stdout = dup (0);
- original_stderr = dup (1);
- dup2 (fd, 0);
- dup2 (fd, 1);
+ original_stdout = dup( 0 );
+ original_stderr = dup( 1 );
+ dup2 ( fd, 0 );
+ dup2 ( fd, 1 );
}
- if (force)
+ if ( !list_empty( force ) )
{
original_noexec = globs.noexec;
globs.noexec = 0;
@@ -1360,95 +1378,83 @@ LIST * builtin_update_now( PARSE * parse, FRAME * frame )
globs.quitquick = 0;
}
- if (continue_)
+ if ( !list_empty( continue_ ) )
{
original_quitquick = globs.quitquick;
globs.quitquick = 0;
}
- targets_count = list_length( targets );
- targets2 = (const char * *)BJAM_MALLOC( targets_count * sizeof( char * ) );
- for (i = 0 ; targets; targets = list_next( targets ) )
- targets2[ i++ ] = targets->string;
- status |= make( targets_count, targets2, anyhow);
- free( targets );
+ status = make( targets, anyhow );
- if (force)
+ if ( !list_empty( force ) )
{
globs.noexec = original_noexec;
globs.quitquick = original_quitquick;
}
- if (continue_)
+ if ( !list_empty( continue_ ) )
{
globs.quitquick = original_quitquick;
}
- if (log)
+ if ( !list_empty( log ) )
{
/* 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);
- dup2 (original_stderr, 1);
- close (original_stdout);
- close (original_stderr);
+ fflush( stdout );
+ fflush( stderr );
+ dup2( original_stdout, 0 );
+ dup2( original_stderr, 1 );
+ close( original_stdout );
+ close( original_stderr );
}
last_update_now_status = status;
- if (status == 0)
- return list_new (L0, newstr ("ok"));
+ if ( status == 0 )
+ return list_new( object_copy( constant_ok ) );
else
return L0;
}
-LIST * builtin_search_for_target( PARSE * parse, FRAME * frame )
-{
- LIST * arg1 = lol_get( frame->args, 0 );
- LIST * arg2 = lol_get( frame->args, 1 );
- TARGET * t = search_for_target( arg1->string, arg2 );
- return list_new( L0, t->name );
-}
-
-LIST * builtin_import_module( PARSE * parse, FRAME * frame )
+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 = arg2 ? bindmodule( arg2->string ) : root_module();
+ module_t * m = !list_empty( arg2 ) ? bindmodule( list_front( arg2 ) ) : root_module();
import_module( arg1, m );
return L0;
}
-LIST * builtin_imported_modules( PARSE * parse, FRAME * frame )
+LIST * builtin_imported_modules( FRAME * frame, int flags )
{
LIST * arg0 = lol_get( frame->args, 0 );
- return imported_modules( bindmodule( arg0 ? arg0->string : 0 ) );
+ return imported_modules( bindmodule( !list_empty( arg0 ) ? list_front( arg0 ) : 0 ) );
}
-LIST * builtin_instance( PARSE * parse, FRAME * frame )
+LIST * builtin_instance( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
LIST * arg2 = lol_get( frame->args, 1 );
- module_t * const instance = bindmodule( arg1->string );
- module_t * const class_module = bindmodule( arg2->string );
+ module_t * const instance = bindmodule( list_front( arg1 ) );
+ module_t * const class_module = bindmodule( list_front( arg2 ) );
instance->class_module = class_module;
+ module_set_fixed_variables( instance, class_module->num_fixed_variables );
return L0;
}
-LIST * builtin_sort( PARSE * parse, FRAME * frame )
+LIST * builtin_sort( FRAME * frame, int flags )
{
LIST * arg1 = lol_get( frame->args, 0 );
return list_sort( arg1 );
}
-LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
+LIST * builtin_normalize_path( FRAME * frame, int flags )
{
LIST * arg = lol_get( frame->args, 0 );
@@ -1468,7 +1474,8 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
/* Number of '..' elements seen and not processed yet. */
int dotdots = 0;
int rooted = 0;
- char * result = 0;
+ OBJECT * result = 0;
+ LISTITER arg_iter = list_begin( arg ), 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
@@ -1476,16 +1483,16 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
*/
string_new( in );
string_push_back( in, '/' );
- for ( ; arg; arg = list_next( arg ) )
+ for ( ; arg_iter != arg_end; arg_iter = list_next( arg_iter ) )
{
- if ( arg->string[ 0 ] != '\0' )
+ if ( object_str( list_item( arg_iter ) )[ 0 ] != '\0' )
{
if ( in->size == 1 )
- rooted = ( ( arg->string[ 0 ] == '/' ) ||
- ( arg->string[ 0 ] == '\\' ) );
+ rooted = ( ( object_str( list_item( arg_iter ) )[ 0 ] == '/' ) ||
+ ( object_str( list_item( arg_iter ) )[ 0 ] == '\\' ) );
else
string_append( in, "/" );
- string_append( in, arg->string );
+ string_append( in, object_str( list_item( arg_iter ) ) );
}
}
@@ -1544,7 +1551,12 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
*/
if ( dotdots )
{
- if ( rooted ) return L0;
+ if ( rooted )
+ {
+ string_free( out );
+ string_free( in );
+ return L0;
+ }
do
string_append( out, "/.." );
while ( --dotdots );
@@ -1561,34 +1573,32 @@ LIST * builtin_normalize_path( PARSE * parse, FRAME * frame )
* the original path was rooted and we have an empty path we need to add
* back the '/'.
*/
- result = newstr( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
+ result = object_new( out->size ? out->value + !rooted : ( rooted ? "/" : "." ) );
string_free( out );
string_free( in );
- return list_new( 0, result );
+ return list_new( result );
}
-LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_native_rule( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
LIST * rule_name = lol_get( frame->args, 1 );
- module_t * module = bindmodule( module_name->string );
+ module_t * module = bindmodule( list_front( module_name ) );
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+ native_rule_t * np;
+ if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
{
- new_rule_body( module, np->name, np->arguments, np->procedure, 1 );
+ new_rule_body( module, np->name, np->procedure, 1 );
}
else
{
backtrace_line( frame->prev );
- printf( "error: no native rule \"%s\" defined in module \"%s\"\n",
- n.name, module->name );
+ printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
+ object_str( list_front( rule_name ) ), object_str( module->name ) );
backtrace( frame->prev );
exit( 1 );
}
@@ -1596,40 +1606,39 @@ LIST * builtin_native_rule( PARSE * parse, FRAME * frame )
}
-LIST * builtin_has_native_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_has_native_rule( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
LIST * rule_name = lol_get( frame->args, 1 );
LIST * version = lol_get( frame->args, 2 );
- module_t * module = bindmodule( module_name->string );
+ module_t * module = bindmodule( list_front( module_name ) );
- native_rule_t n;
- native_rule_t * np = &n;
- n.name = rule_name->string;
- if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+ native_rule_t * np;
+ if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, list_front( rule_name ) ) ) )
{
- int expected_version = atoi( version->string );
+ int expected_version = atoi( object_str( list_front( version ) ) );
if ( np->version == expected_version )
- return list_new( 0, newstr( "true" ) );
+ return list_new( object_copy( constant_true ) );
}
return L0;
}
-LIST * builtin_user_module( PARSE * parse, FRAME * frame )
+LIST * builtin_user_module( FRAME * frame, int flags )
{
LIST * module_name = lol_get( frame->args, 0 );
- for ( ; module_name; module_name = module_name->next )
+ LISTITER iter = list_begin( module_name ), end = list_end( module_name );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- module_t * m = bindmodule( module_name->string );
+ module_t * m = bindmodule( list_item( iter ) );
m->user_module = 1;
}
return L0;
}
-LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
+LIST * builtin_nearest_user_location( FRAME * frame, int flags )
{
FRAME * nearest_user_frame =
frame->module->user_module ? frame : frame->prev_user;
@@ -1637,33 +1646,33 @@ LIST * builtin_nearest_user_location( PARSE * parse, FRAME * frame )
return L0;
{
- LIST * result = 0;
- char * file;
+ LIST * result = L0;
+ const char * file;
int line;
char buf[32];
- get_source_line( nearest_user_frame->procedure, &file, &line );
+ get_source_line( nearest_user_frame, &file, &line );
sprintf( buf, "%d", line );
- result = list_new( result, newstr( file ) );
- result = list_new( result, newstr( buf ) );
+ result = list_push_back( result, object_new( file ) );
+ result = list_push_back( result, object_new( buf ) );
return result;
}
}
-LIST * builtin_check_if_file( PARSE * parse, FRAME * frame )
+LIST * builtin_check_if_file( FRAME * frame, int flags )
{
LIST * name = lol_get( frame->args, 0 );
- return file_is_file( name->string ) == 1
- ? list_new( 0, newstr( "true" ) )
+ return file_is_file( list_front( name ) ) == 1
+ ? list_new( object_copy( constant_true ) )
: L0 ;
}
-LIST * builtin_md5( PARSE * parse, FRAME * frame )
+LIST * builtin_md5( FRAME * frame, int flags )
{
LIST * l = lol_get( frame->args, 0 );
- char* s = l->string;
+ const char* s = object_str( list_front( l ) );
md5_state_t state;
md5_byte_t digest[16];
@@ -1671,36 +1680,36 @@ LIST * builtin_md5( PARSE * parse, FRAME * frame )
int di;
- md5_init(&state);
- md5_append(&state, (const md5_byte_t *)s, strlen(s));
- md5_finish(&state, digest);
+ md5_init( &state );
+ md5_append( &state, (const md5_byte_t *)s, strlen(s) );
+ md5_finish( &state, digest );
for (di = 0; di < 16; ++di)
- sprintf(hex_output + di * 2, "%02x", digest[di]);
+ sprintf( hex_output + di * 2, "%02x", digest[di] );
- return list_new (0, newstr(hex_output));
+ return list_new( object_new( hex_output ) );
}
-LIST *builtin_file_open( PARSE *parse, FRAME *frame )
+LIST *builtin_file_open( FRAME * frame, int flags )
{
- char* name = lol_get(frame->args, 0)->string;
- char* mode = lol_get(frame->args, 1)->string;
+ const char * name = object_str( list_front( lol_get( frame->args, 0 ) ) );
+ const char * mode = object_str( list_front( lol_get( frame->args, 1 ) ) );
int fd;
char buffer[sizeof("4294967295")];
- if (strcmp(mode, "w") == 0)
+ if ( strcmp(mode, "w") == 0 )
{
- fd = open(name, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ fd = open( name, O_WRONLY|O_CREAT|O_TRUNC, 0666 );
}
else
{
- fd = open(name, O_RDONLY);
+ fd = open( name, O_RDONLY );
}
if (fd != -1)
{
- sprintf(buffer, "%d", fd);
- return list_new(L0, newstr(buffer));
+ sprintf( buffer, "%d", fd );
+ return list_new( object_new( buffer ) );
}
else
{
@@ -1708,52 +1717,53 @@ LIST *builtin_file_open( PARSE *parse, FRAME *frame )
}
}
-LIST *builtin_pad( PARSE *parse, FRAME *frame )
+LIST *builtin_pad( FRAME * frame, int flags )
{
- char *string = lol_get(frame->args, 0)->string;
- char *width_s = lol_get(frame->args, 1)->string;
+ OBJECT * string = list_front( lol_get( frame->args, 0 ) );
+ const char * width_s = object_str( list_front( lol_get( frame->args, 1 ) ) );
- int current = strlen (string);
- int desired = atoi(width_s);
+ int current = strlen( object_str( string ) );
+ int desired = atoi( width_s );
if (current >= desired)
- return list_new (L0, string);
+ return list_new( object_copy( string ) );
else
{
- char *buffer = malloc (desired + 1);
+ char * buffer = BJAM_MALLOC( desired + 1 );
int i;
- LIST *result;
+ LIST * result;
- strcpy (buffer, string);
- for (i = current; i < desired; ++i)
+ strcpy( buffer, object_str( string ) );
+ for ( i = current; i < desired; ++i )
buffer[i] = ' ';
buffer[desired] = '\0';
- result = list_new (L0, newstr (buffer));
- free (buffer);
+ result = list_new( object_new( buffer ) );
+ BJAM_FREE( buffer );
return result;
}
}
-LIST *builtin_precious( PARSE *parse, FRAME *frame )
+LIST *builtin_precious( FRAME * frame, int flags )
{
- LIST* targets = lol_get(frame->args, 0);
+ LIST * targets = lol_get(frame->args, 0);
- for ( ; targets; targets = list_next( targets ) )
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET* t = bindtarget (targets->string);
+ TARGET* t = bindtarget( list_item( iter ) );
t->flags |= T_FLAG_PRECIOUS;
}
return L0;
}
-LIST *builtin_self_path( PARSE *parse, FRAME *frame )
+LIST *builtin_self_path( FRAME * frame, int flags )
{
- extern char *saved_argv0;
- char *p = executable_path (saved_argv0);
- if (p)
+ extern const char * saved_argv0;
+ char * p = executable_path( saved_argv0 );
+ if ( p )
{
- LIST* result = list_new (0, newstr (p));
- free(p);
+ LIST* result = list_new( object_new( p ) );
+ free( p );
return result;
}
else
@@ -1762,13 +1772,13 @@ LIST *builtin_self_path( PARSE *parse, FRAME *frame )
}
}
-LIST *builtin_makedir( PARSE *parse, FRAME *frame )
+LIST *builtin_makedir( FRAME * frame, int flags )
{
- LIST *path = lol_get(frame->args, 0);
+ LIST * path = lol_get( frame->args, 0 );
- if (file_mkdir(path->string) == 0)
+ if ( file_mkdir( object_str( list_front( path ) ) ) == 0 )
{
- LIST *result = list_new (0, newstr(path->string));
+ LIST * result = list_new( object_copy( list_front( path ) ) );
return result;
}
else
@@ -1779,13 +1789,13 @@ LIST *builtin_makedir( PARSE *parse, FRAME *frame )
#ifdef HAVE_PYTHON
-LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
+LIST * builtin_python_import_rule( FRAME * frame, int flags )
{
static int first_time = 1;
- char * python_module = lol_get( frame->args, 0 )->string;
- char * python_function = lol_get( frame->args, 1 )->string;
- char * jam_module = lol_get( frame->args, 2 )->string;
- char * jam_rule = lol_get( frame->args, 3 )->string;
+ 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 ) ) );
+ OBJECT * jam_module = list_front( lol_get( frame->args, 2 ) );
+ OBJECT * jam_rule = list_front( lol_get( frame->args, 3 ) );
PyObject * pName;
PyObject * pModule;
@@ -1799,29 +1809,19 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
*/
LIST * extra = 0;
module_t * outer_module = frame->module;
+ LISTITER iter, end;
first_time = 0;
- if ( outer_module != root_module() )
- {
- exit_module( outer_module );
- enter_module( root_module() );
- }
-
- extra = var_get( "EXTRA_PYTHONPATH" );
-
- if ( outer_module != root_module() )
- {
- exit_module( root_module() );
- enter_module( outer_module );
- }
+ extra = var_get( root_module(), constant_extra_pythonpath );
- for ( ; extra; extra = extra->next )
+ iter = list_begin( extra ), end = list_end( extra );
+ for ( ; iter != end; iter = list_next( iter ) )
{
string buf[ 1 ];
string_new( buf );
string_append( buf, "import sys\nsys.path.append(\"" );
- string_append( buf, extra->string );
+ string_append( buf, object_str( list_item( iter ) ) );
string_append( buf, "\")\n" );
PyRun_SimpleString( buf->value );
string_free( buf );
@@ -1840,12 +1840,7 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
if ( pFunc && PyCallable_Check( pFunc ) )
{
module_t * m = bindmodule( jam_module );
- RULE * r = bindrule( jam_rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( pFunc );
-
- r->python_function = pFunc;
+ new_rule_body( m, jam_rule, function_python( pFunc, 0 ), 0 );
}
else
{
@@ -1866,7 +1861,7 @@ LIST * builtin_python_import_rule( PARSE * parse, FRAME * frame )
#endif
-void lol_build( LOL * lol, char * * elements )
+void lol_build( LOL * lol, const char * * elements )
{
LIST * l = L0;
lol_init( lol );
@@ -1880,7 +1875,7 @@ void lol_build( LOL * lol, char * * elements )
}
else
{
- l = list_new( l, newstr( *elements ) );
+ l = list_push_back( l, object_new( *elements ) );
}
++elements;
}
@@ -1900,22 +1895,21 @@ void lol_build( LOL * lol, char * * elements )
PyObject* bjam_call( PyObject * self, PyObject * args )
{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
- char * rulename;
+ FRAME inner[ 1 ];
+ LIST * result;
+ PARSE * p;
+ OBJECT * rulename;
/* Build up the list of arg lists. */
frame_init( inner );
inner->prev = 0;
inner->prev_user = 0;
- inner->module = bindmodule( "python_interface" );
- inner->procedure = 0;
+ inner->module = bindmodule( constant_python_interface );
/* Extract the rule name and arguments from 'args'. */
/* PyTuple_GetItem returns borrowed reference. */
- rulename = PyString_AsString( PyTuple_GetItem( args, 0 ) );
+ rulename = object_new( PyString_AsString( PyTuple_GetItem( args, 0 ) ) );
{
int i = 1;
int size = PyTuple_Size( args );
@@ -1924,7 +1918,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
PyObject * a = PyTuple_GetItem( args, i );
if ( PyString_Check( a ) )
{
- lol_add( inner->args, list_new( 0, newstr(
+ lol_add( inner->args, list_new( object_new(
PyString_AsString( a ) ) ) );
}
else if ( PySequence_Check( a ) )
@@ -1942,7 +1936,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
printf( "Invalid parameter type passed from Python\n" );
exit( 1 );
}
- l = list_new( l, newstr( s ) );
+ l = list_push_back( l, object_new( s ) );
Py_DECREF( e );
}
lol_add( inner->args, l );
@@ -1951,6 +1945,7 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
}
result = evaluate_rule( rulename, inner );
+ object_free( rulename );
frame_free( inner );
@@ -1958,10 +1953,10 @@ PyObject* bjam_call( PyObject * self, PyObject * args )
{
PyObject * pyResult = PyList_New( list_length( result ) );
int i = 0;
- while ( result )
+ LISTITER iter = list_begin( result ), end = list_end( result );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- PyList_SetItem( pyResult, i, PyString_FromString( result->string ) );
- result = list_next( result );
+ PyList_SetItem( pyResult, i, PyString_FromString( object_str( list_item( iter ) ) ) );
i += 1;
}
list_free( result );
@@ -1988,6 +1983,8 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args )
PyObject * bjam_signature = NULL;
module_t * m;
RULE * r;
+ OBJECT * module_name;
+ OBJECT * rule_name;
if ( !PyArg_ParseTuple( args, "ssO|O:import_rule",
&module, &rule, &func, &bjam_signature ) )
@@ -2000,29 +1997,15 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args )
return NULL;
}
- m = bindmodule( *module ? module : 0 );
- r = bindrule( rule, m );
-
- /* Make pFunc owned. */
- Py_INCREF( func );
-
- r->python_function = func;
- r->arguments = 0;
-
- if (bjam_signature)
+ module_name = *module ? object_new( module ) : 0;
+ m = bindmodule( module_name );
+ if( module_name )
{
- argument_list * arg_list = args_new();
- Py_ssize_t i;
-
- Py_ssize_t s = PySequence_Size (bjam_signature);
- for (i = 0; i < s; ++i)
- {
- PyObject* v = PySequence_GetItem (bjam_signature, i);
- lol_add(arg_list->data, list_from_python (v));
- Py_DECREF(v);
- }
- r->arguments = arg_list;
+ 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 );
Py_INCREF( Py_None );
return Py_None;
@@ -2048,6 +2031,8 @@ PyObject * bjam_define_action( PyObject * self, PyObject * args )
LIST * bindlist = L0;
int n;
int i;
+ OBJECT * name_str;
+ FUNCTION * body_func;
if ( !PyArg_ParseTuple( args, "ssO!i:define_action", &name, &body,
&PyList_Type, &bindlist_python, &flags ) )
@@ -2063,10 +2048,14 @@ PyObject * bjam_define_action( PyObject * self, PyObject * args )
"bind list has non-string type" );
return NULL;
}
- bindlist = list_new( bindlist, PyString_AsString( next ) );
+ bindlist = list_push_back( bindlist, object_new( PyString_AsString( next ) ) );
}
- new_rule_actions( root_module(), name, newstr( body ), bindlist, flags );
+ name_str = object_new( name );
+ body_func = function_compile_actions( body, constant_builtin, -1 );
+ new_rule_actions( root_module(), name_str, body_func, bindlist, flags );
+ function_free( body_func );
+ object_free( name_str );
Py_INCREF( Py_None );
return Py_None;
@@ -2083,17 +2072,20 @@ PyObject * bjam_variable( PyObject * self, PyObject * args )
LIST * value;
PyObject * result;
int i;
+ OBJECT * varname;
+ LISTITER iter, end;
if ( !PyArg_ParseTuple( args, "s", &name ) )
return NULL;
- enter_module( root_module() );
- value = var_get( name );
- exit_module( root_module() );
+ varname = object_new( name );
+ value = var_get( root_module(), varname );
+ object_free( varname );
+ iter = list_begin( value ), end = list_end( value );
result = PyList_New( list_length( value ) );
- for ( i = 0; value; value = list_next( value ), ++i )
- PyList_SetItem( result, i, PyString_FromString( value->string ) );
+ for ( i = 0; iter != end; iter = list_next( iter ), ++i )
+ PyList_SetItem( result, i, PyString_FromString( object_str( list_item( iter ) ) ) );
return result;
}
@@ -2106,19 +2098,28 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args )
for ( ; f = f->prev; )
{
- PyObject * tuple = PyTuple_New( 4 );
- char * file;
- int line;
- char buf[ 32 ];
+ PyObject * tuple = PyTuple_New( 4 );
+ const char * file;
+ int line;
+ char buf[ 32 ];
+ string module_name[1];
- get_source_line( f->procedure, &file, &line );
+ get_source_line( f, &file, &line );
sprintf( buf, "%d", line );
+ string_new( module_name );
+ if ( f->module->name )
+ {
+ string_append( module_name, object_str( f->module->name ) );
+ string_append( module_name, "." );
+ }
/* PyTuple_SetItem steals reference. */
PyTuple_SetItem( tuple, 0, PyString_FromString( file ) );
PyTuple_SetItem( tuple, 1, PyString_FromString( buf ) );
- PyTuple_SetItem( tuple, 2, PyString_FromString( f->module->name ) );
- PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
+ PyTuple_SetItem( tuple, 2, PyString_FromString( module_name->value ) );
+ PyTuple_SetItem( tuple, 3, PyString_FromString( f->rulename ) );
+
+ string_free( module_name );
PyList_Append( result, tuple );
Py_DECREF( tuple );
@@ -2128,9 +2129,10 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args )
PyObject * bjam_caller( PyObject * self, PyObject * args )
{
- PyObject *result = PyString_FromString(
- frame_before_python_call->prev->module->name);
- return result;
+ const char * s = frame_before_python_call->prev->module->name ?
+ object_str( frame_before_python_call->prev->module->name ) :
+ "";
+ return PyString_FromString( s );
}
#endif /* #ifdef HAVE_PYTHON */
@@ -2189,7 +2191,7 @@ PyObject * bjam_caller( PyObject * self, PyObject * args )
* should Windows ever 'fix' this feature.
* (03.06.2008.) (Jurko)
*/
- static FILE * windows_popen_wrapper( char * command, char * mode )
+ static FILE * windows_popen_wrapper( const char * command, const char * mode )
{
int extra_command_quotes_needed = ( strchr( command, '"' ) != 0 );
string quoted_command;
@@ -2214,18 +2216,18 @@ PyObject * bjam_caller( PyObject * self, PyObject * args )
#endif
-static char * rtrim(char *s)
+static char * rtrim( char * s )
{
- char *p = s;
- while(*p) ++p;
- for(--p; p >= s && isspace(*p); *p-- = 0);
+ char * p = s;
+ while ( *p ) ++p;
+ for ( --p; p >= s && isspace( *p ); *p-- = 0 );
return s;
}
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
{
LIST * command = lol_get( frame->args, 0 );
- LIST * result = 0;
+ LIST * result = L0;
string s;
int ret;
char buffer[ 1024 ];
@@ -2239,17 +2241,17 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
{
int a = 1;
LIST * arg = lol_get( frame->args, a );
- while ( arg )
+ while ( !list_empty( arg ) )
{
- if ( strcmp( "exit-status", arg->string ) == 0 )
+ if ( strcmp( "exit-status", object_str( list_front( arg ) ) ) == 0 )
{
exit_status_opt = 1;
}
- else if ( strcmp( "no-output", arg->string ) == 0 )
+ else if ( strcmp( "no-output", object_str( list_front( arg ) ) ) == 0 )
{
no_output_opt = 1;
}
- else if ( strcmp("strip-eol", arg->string) == 0 )
+ else if ( strcmp("strip-eol", object_str( list_front( arg ) ) ) == 0 )
{
strip_eol_opt = 1;
}
@@ -2263,7 +2265,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
*/
fflush( NULL );
- p = popen( command->string, "r" );
+ p = popen( object_str( list_front( command ) ), "r" );
if ( p == NULL )
return L0;
@@ -2283,7 +2285,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
exit_status = pclose( p );
/* The command output is returned first. */
- result = list_new( L0, newstr( s.value ) );
+ result = list_new( object_new( s.value ) );
string_free( &s );
/* The command exit result next. */
@@ -2294,7 +2296,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
else
exit_status = -1;
sprintf( buffer, "%d", exit_status );
- result = list_new( result, newstr( buffer ) );
+ result = list_push_back( result, object_new( buffer ) );
}
return result;
@@ -2302,7 +2304,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame )
#else /* #ifdef HAVE_POPEN */
-LIST * builtin_shell( PARSE * parse, FRAME * frame )
+LIST * builtin_shell( FRAME * frame, int flags )
{
return L0;
}
diff --git a/tools/build/v2/engine/builtins.h b/tools/build/v2/engine/builtins.h
index 5fed07c968..b8c086fb4f 100644
--- a/tools/build/v2/engine/builtins.h
+++ b/tools/build/v2/engine/builtins.h
@@ -21,47 +21,46 @@ void init_property_set();
void init_sequence();
void init_order();
-LIST *builtin_calc( PARSE *parse, FRAME *args );
-LIST *builtin_depends( PARSE *parse, FRAME *args );
-LIST *builtin_rebuilds( PARSE *parse, FRAME *args );
-LIST *builtin_echo( PARSE *parse, FRAME *args );
-LIST *builtin_exit( PARSE *parse, FRAME *args );
-LIST *builtin_flags( PARSE *parse, FRAME *args );
-LIST *builtin_glob( PARSE *parse, FRAME *args );
-LIST *builtin_glob_recursive( PARSE *parse, FRAME *frame );
-LIST *builtin_subst( PARSE *parse, FRAME *args );
-LIST *builtin_match( PARSE *parse, FRAME *args );
-LIST *builtin_split_by_characters( PARSE *parse, FRAME *args );
-LIST *builtin_hdrmacro( PARSE *parse, FRAME *args );
-LIST *builtin_rulenames( PARSE *parse, FRAME *args );
-LIST *builtin_varnames( PARSE *parse, FRAME *args );
-LIST *builtin_delete_module( PARSE *parse, FRAME *args );
-LIST *builtin_import( PARSE *parse, FRAME *args );
-LIST *builtin_export( PARSE *parse, FRAME *args );
-LIST *builtin_caller_module( PARSE *parse, FRAME *args );
-LIST *builtin_backtrace( PARSE *parse, FRAME *args );
-LIST *builtin_pwd( PARSE *parse, FRAME *args );
-LIST *builtin_update( PARSE *parse, FRAME *args );
-LIST *builtin_update_now( PARSE *parse, FRAME *args );
-LIST *builtin_search_for_target( PARSE *parse, FRAME *args );
-LIST *builtin_import_module( PARSE *parse, FRAME *args );
-LIST *builtin_imported_modules( PARSE *parse, FRAME *frame );
-LIST *builtin_instance( PARSE *parse, FRAME *frame );
-LIST *builtin_sort( PARSE *parse, FRAME *frame );
-LIST *builtin_normalize_path( PARSE *parse, FRAME *frame );
-LIST *builtin_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_has_native_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_user_module( PARSE *parse, FRAME *frame );
-LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame );
-LIST *builtin_check_if_file( PARSE *parse, FRAME *frame );
-LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame );
-LIST *builtin_shell( PARSE *parse, FRAME *frame );
-LIST *builtin_md5( PARSE *parse, FRAME *frame );
-LIST *builtin_file_open( PARSE *parse, FRAME *frame );
-LIST *builtin_pad( PARSE *parse, FRAME *frame );
-LIST *builtin_precious( PARSE *parse, FRAME *frame );
-LIST *builtin_self_path( PARSE *parse, FRAME *frame );
-LIST *builtin_makedir( PARSE *parse, FRAME *frame );
+LIST *builtin_calc( FRAME * frame, int flags );
+LIST *builtin_depends( FRAME * frame, int flags );
+LIST *builtin_rebuilds( FRAME * frame, int flags );
+LIST *builtin_echo( FRAME * frame, int flags );
+LIST *builtin_exit( FRAME * frame, int flags );
+LIST *builtin_flags( FRAME * frame, int flags );
+LIST *builtin_glob( FRAME * frame, int flags );
+LIST *builtin_glob_recursive( FRAME * frame, int flags );
+LIST *builtin_subst( FRAME * frame, int flags );
+LIST *builtin_match( FRAME * frame, int flags );
+LIST *builtin_split_by_characters( FRAME * frame, int flags );
+LIST *builtin_hdrmacro( FRAME * frame, int flags );
+LIST *builtin_rulenames( FRAME * frame, int flags );
+LIST *builtin_varnames( FRAME * frame, int flags );
+LIST *builtin_delete_module( FRAME * frame, int flags );
+LIST *builtin_import( FRAME * frame, int flags );
+LIST *builtin_export( FRAME * frame, int flags );
+LIST *builtin_caller_module( FRAME * frame, int flags );
+LIST *builtin_backtrace( FRAME * frame, int flags );
+LIST *builtin_pwd( FRAME * frame, int flags );
+LIST *builtin_update( FRAME * frame, int flags );
+LIST *builtin_update_now( FRAME * frame, int flags );
+LIST *builtin_import_module( FRAME * frame, int flags );
+LIST *builtin_imported_modules( FRAME * frame, int flags );
+LIST *builtin_instance( FRAME * frame, int flags );
+LIST *builtin_sort( FRAME * frame, int flags );
+LIST *builtin_normalize_path( FRAME * frame, int flags );
+LIST *builtin_native_rule( FRAME * frame, int flags );
+LIST *builtin_has_native_rule( FRAME * frame, int flags );
+LIST *builtin_user_module( FRAME * frame, int flags );
+LIST *builtin_nearest_user_location( FRAME * frame, int flags );
+LIST *builtin_check_if_file( FRAME * frame, int flags );
+LIST *builtin_python_import_rule( FRAME * frame, int flags );
+LIST *builtin_shell( FRAME * frame, int flags );
+LIST *builtin_md5( FRAME * frame, int flags );
+LIST *builtin_file_open( FRAME * frame, int flags );
+LIST *builtin_pad( FRAME * frame, int flags );
+LIST *builtin_precious( FRAME * frame, int flags );
+LIST *builtin_self_path( FRAME * frame, int flags );
+LIST *builtin_makedir( FRAME * frame, int flags );
void backtrace( FRAME *frame );
extern int last_update_now_status;
diff --git a/tools/build/v2/engine/class.c b/tools/build/v2/engine/class.c
index ff4ec56807..8871d1113b 100644
--- a/tools/build/v2/engine/class.c
+++ b/tools/build/v2/engine/class.c
@@ -7,7 +7,7 @@
#include "variable.h"
#include "frames.h"
#include "rules.h"
-#include "newstr.h"
+#include "object.h"
#include "hash.h"
@@ -17,28 +17,28 @@ static struct hash * classes = 0;
static void check_defined( LIST * class_names )
{
- for ( ; class_names; class_names = class_names->next )
+ LISTITER iter = list_begin( class_names ), end = list_end( class_names );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- char * * p = &class_names->string;
- if ( !hashcheck( classes, (HASHDATA * *)&p ) )
+ if ( !hash_find( classes, list_item( iter ) ) )
{
- printf( "Class %s is not defined\n", class_names->string );
+ printf( "Class %s is not defined\n", object_str( list_item( iter ) ) );
abort();
}
}
}
-static char * class_module_name( char * declared_name )
+static OBJECT * class_module_name( OBJECT * declared_name )
{
string name[ 1 ];
- char * result;
+ OBJECT * result;
string_new( name );
string_append( name, "class@" );
- string_append( name, declared_name );
+ string_append( name, object_str( declared_name ) );
- result = newstr( name->value );
+ result = object_new( name->value );
string_free( name );
return result;
@@ -47,7 +47,7 @@ static char * class_module_name( char * declared_name )
struct import_base_data
{
- char * base_name;
+ OBJECT * base_name;
module_t * base_module;
module_t * class_module;
};
@@ -60,14 +60,19 @@ static void import_base_rule( void * r_, void * d_ )
RULE * ir2;
struct import_base_data * d = (struct import_base_data *)d_;
string qualified_name[ 1 ];
+ OBJECT * qname;
string_new ( qualified_name );
- string_append ( qualified_name, d->base_name );
+ string_append ( qualified_name, object_str( d->base_name ) );
string_push_back( qualified_name, '.' );
- string_append ( qualified_name, r->name );
+ string_append ( qualified_name, object_str( r->name ) );
+
+ qname = object_new( qualified_name->value );
ir1 = import_rule( r, d->class_module, r->name );
- ir2 = import_rule( r, d->class_module, qualified_name->value );
+ ir2 = import_rule( r, d->class_module, qname );
+
+ object_free( qname );
/* Copy 'exported' flag. */
ir1->exported = ir2->exported = r->exported;
@@ -75,7 +80,10 @@ static void import_base_rule( void * r_, void * d_ )
/* If we are importing a class method, localize it. */
if ( ( r->module == d->base_module ) || ( r->module->class_module &&
( r->module->class_module == d->base_module ) ) )
- ir1->module = ir2->module = d->class_module;
+ {
+ rule_localize( ir1, d->class_module );
+ rule_localize( ir2, d->class_module );
+ }
string_free( qualified_name );
}
@@ -87,55 +95,73 @@ static void import_base_rule( void * r_, void * d_ )
* marked as exported.
*/
-static void import_base_rules( module_t * class, char * base )
+static void import_base_rules( module_t * class_, OBJECT * base )
{
- module_t * base_module = bindmodule( class_module_name( base ) );
+ OBJECT * module_name = class_module_name( base );
+ module_t * base_module = bindmodule( module_name );
+ LIST * imported;
struct import_base_data d;
d.base_name = base;
d.base_module = base_module;
- d.class_module = class;
+ d.class_module = class_;
+ object_free( module_name );
if ( base_module->rules )
hashenumerate( base_module->rules, import_base_rule, &d );
- import_module( imported_modules( base_module ), class );
+ imported = imported_modules( base_module );
+ import_module( imported, class_ );
+ list_free( imported );
}
-char * make_class_module( LIST * xname, LIST * bases, FRAME * frame )
+OBJECT * make_class_module( LIST * xname, LIST * bases, FRAME * frame )
{
- char * name = class_module_name( xname->string );
- char * * pp = &xname->string;
+ OBJECT * name = class_module_name( list_front( xname ) );
+ OBJECT * * pp;
module_t * class_module = 0;
module_t * outer_module = frame->module;
+ int found;
+ LISTITER iter, end;
if ( !classes )
- classes = hashinit( sizeof( char * ), "classes" );
+ classes = hashinit( sizeof( OBJECT * ), "classes" );
- if ( hashcheck( classes, (HASHDATA * *)&pp ) )
+ pp = (OBJECT * *)hash_insert( classes, list_front( xname ), &found );
+ if ( !found )
{
- printf( "Class %s already defined\n", xname->string );
- abort();
+ *pp = object_copy( list_front( xname ) );
}
else
{
- hashenter( classes, (HASHDATA * *)&pp );
+ printf( "Class %s already defined\n", object_str( list_front( xname ) ) );
+ abort();
}
check_defined( bases );
class_module = bindmodule( name );
- exit_module( outer_module );
- enter_module( class_module );
+ var_set( class_module, constant_name, xname, VAR_SET );
+ var_set( class_module, constant_bases, bases, VAR_SET );
- var_set( "__name__", xname, VAR_SET );
- var_set( "__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 ) );
- exit_module( class_module );
- enter_module( outer_module );
+ return name;
+}
- for ( ; bases; bases = bases->next )
- import_base_rules( class_module, bases->string );
+static void free_class( void * xclass, void * data )
+{
+ object_free( *(OBJECT * *)xclass );
+}
- return name;
+void class_done( void )
+{
+ if( classes )
+ {
+ hashenumerate( classes, free_class, (void *)0 );
+ hashdone( classes );
+ classes = 0;
+ }
}
diff --git a/tools/build/v2/engine/class.h b/tools/build/v2/engine/class.h
index f7faeff62e..256d298b53 100644
--- a/tools/build/v2/engine/class.h
+++ b/tools/build/v2/engine/class.h
@@ -8,6 +8,7 @@
#include "lists.h"
#include "frames.h"
-char* make_class_module(LIST* xname, LIST* bases, FRAME* frame);
+OBJECT * make_class_module( LIST * xname, LIST * bases, FRAME * frame );
+void class_done( void );
#endif
diff --git a/tools/build/v2/engine/command.c b/tools/build/v2/engine/command.c
index d2ea068149..8161014c05 100644
--- a/tools/build/v2/engine/command.c
+++ b/tools/build/v2/engine/command.c
@@ -33,10 +33,11 @@
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 = ( shell && !strcmp(shell->string,"%") && !list_next(shell) );
+ int no_limit = ( iter != end && !strcmp( object_str( list_item( iter ) ), "%") && list_next( iter ) == end );
int max_line = MAXLINE;
- int allocated = -1;
+ FRAME frame[1];
cmd->rule = rule;
cmd->shell = shell;
@@ -45,27 +46,20 @@ CMD * cmd_new( RULE * rule, LIST * targets, LIST * sources, LIST * shell )
lol_init( &cmd->args );
lol_add( &cmd->args, targets );
lol_add( &cmd->args, sources );
- cmd->buf = 0;
+ string_new( cmd->buf );
- do
- {
- BJAM_FREE( cmd->buf ); /* free any buffer from previous iteration */
-
- cmd->buf = (char*)BJAM_MALLOC_ATOMIC( max_line + 1 );
-
- if ( cmd->buf == 0 )
- break;
-
- allocated = var_string( rule->actions->command, cmd->buf, max_line, &cmd->args );
-
- max_line = max_line * 2;
- }
- while ( ( allocated < 0 ) && ( max_line < INT_MAX / 2 ) );
+ frame_init( frame );
+ frame->module = rule->module;
+ 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 );
+ frame_free( frame );
if ( !no_limit )
{
/* Bail if the result will not fit in MAXLINE. */
- char * s = cmd->buf;
+ char * s = cmd->buf->value;
while ( *s )
{
size_t l = strcspn( s, "\n" );
@@ -95,6 +89,6 @@ void cmd_free( CMD * cmd )
{
lol_free( &cmd->args );
list_free( cmd->shell );
- BJAM_FREE( cmd->buf );
- BJAM_FREE( (char *)cmd );
+ string_free( cmd->buf );
+ BJAM_FREE( (void *)cmd );
}
diff --git a/tools/build/v2/engine/command.h b/tools/build/v2/engine/command.h
index ddd38e6897..4dad9e254c 100644
--- a/tools/build/v2/engine/command.h
+++ b/tools/build/v2/engine/command.h
@@ -36,6 +36,13 @@
* CMD - an action, ready to be formatted into a buffer and executed.
*/
+#ifndef COMMAND_SW20111118_H
+#define COMMAND_SW20111118_H
+
+#include "lists.h"
+#include "rules.h"
+#include "strings.h"
+
typedef struct _cmd CMD;
struct _cmd
@@ -45,7 +52,7 @@ struct _cmd
RULE * rule; /* rule->actions contains shell script */
LIST * shell; /* $(SHELL) value */
LOL args; /* LISTs for $(<), $(>) */
- char * buf; /* actual commands */
+ string buf[1]; /* actual commands */
};
CMD * cmd_new
@@ -59,3 +66,5 @@ CMD * cmd_new
void cmd_free( CMD * );
#define cmd_next( c ) ( ( c )->next )
+
+#endif
diff --git a/tools/build/v2/engine/compile.c b/tools/build/v2/engine/compile.c
index 2c049aae59..cb08e24c95 100644
--- a/tools/build/v2/engine/compile.c
+++ b/tools/build/v2/engine/compile.c
@@ -16,9 +16,8 @@
# include "parse.h"
# include "compile.h"
# include "variable.h"
-# include "expand.h"
# include "rules.h"
-# include "newstr.h"
+# include "object.h"
# include "make.h"
# include "search.h"
# include "hdrmacro.h"
@@ -27,6 +26,7 @@
# include "strings.h"
# include "builtins.h"
# include "class.h"
+# include "constants.h"
# include <assert.h>
# include <string.h>
@@ -86,15 +86,17 @@
* 01/10/00 (seiwald) - built-ins split out to builtin.c.
*/
-static void debug_compile( int which, char *s, FRAME* frame );
-int glob( char *s, char *c );
+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( PARSE* p );
+void backtrace( FRAME * frame );
+void backtrace_line( FRAME * frame );
+void print_source_line( FRAME * frame );
struct frame * frame_before_python_call;
+static OBJECT * module_scope;
+
void frame_init( FRAME* frame )
{
frame->prev = 0;
@@ -102,7 +104,8 @@ void frame_init( FRAME* frame )
lol_init(frame->args);
frame->module = root_module();
frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
}
@@ -113,907 +116,39 @@ void frame_free( FRAME* frame )
/*
- * compile_append() - append list results of two statements
- *
- * parse->left more compile_append() by left-recursion
- * parse->right single rule
- */
-
-LIST * compile_append( PARSE * parse, FRAME * frame )
-{
- /* Append right to left. */
- return list_append(
- parse_evaluate( parse->left, frame ),
- parse_evaluate( parse->right, frame ) );
-}
-
-
-/*
- * compile_eval() - evaluate if to determine which leg to compile
- *
- * Returns:
- * list if expression true - compile 'then' clause
- * L0 if expression false - compile 'else' clause
- */
-
-static int lcmp( LIST * t, LIST * s )
-{
- int status = 0;
-
- while ( !status && ( t || s ) )
- {
- char *st = t ? t->string : "";
- char *ss = s ? s->string : "";
-
- status = strcmp( st, ss );
-
- t = t ? list_next( t ) : t;
- s = s ? list_next( s ) : s;
- }
-
- return status;
-}
-
-LIST * compile_eval( PARSE * parse, FRAME * frame )
-{
- LIST * ll;
- LIST * lr;
- LIST * s;
- LIST * t;
- int status = 0;
-
- /* Short circuit lr eval for &&, ||, and 'in'. */
-
- ll = parse_evaluate( parse->left, frame );
- lr = 0;
-
- switch ( parse->num )
- {
- case EXPR_AND:
- case EXPR_IN : if ( ll ) goto eval; break;
- case EXPR_OR : if ( !ll ) goto eval; break;
- default: eval: lr = parse_evaluate( parse->right, frame );
- }
-
- /* Now eval. */
- switch ( parse->num )
- {
- case EXPR_NOT: if ( !ll ) status = 1; break;
- case EXPR_AND: if ( ll && lr ) status = 1; break;
- case EXPR_OR : if ( ll || lr ) status = 1; break;
-
- case EXPR_IN:
- /* "a in b": make sure each of ll is equal to something in lr. */
- for ( t = ll; t; t = list_next( t ) )
- {
- for ( s = lr; s; s = list_next( s ) )
- if ( !strcmp( t->string, s->string ) )
- break;
- if ( !s ) break;
- }
- /* No more ll? Success. */
- if ( !t ) status = 1;
- break;
-
- case EXPR_EXISTS: if ( lcmp( ll, L0 ) != 0 ) status = 1; break;
- case EXPR_EQUALS: if ( lcmp( ll, lr ) == 0 ) status = 1; break;
- case EXPR_NOTEQ : if ( lcmp( ll, lr ) != 0 ) status = 1; break;
- case EXPR_LESS : if ( lcmp( ll, lr ) < 0 ) status = 1; break;
- case EXPR_LESSEQ: if ( lcmp( ll, lr ) <= 0 ) status = 1; break;
- case EXPR_MORE : if ( lcmp( ll, lr ) > 0 ) status = 1; break;
- case EXPR_MOREEQ: if ( lcmp( ll, lr ) >= 0 ) status = 1; break;
- }
-
- if ( DEBUG_IF )
- {
- debug_compile( 0, "if", frame );
- list_print( ll );
- printf( "(%d) ", status );
- list_print( lr );
- printf( "\n" );
- }
-
- /* Find something to return. */
- /* In odd circumstances (like "" = "") */
- /* we'll have to return a new string. */
-
- if ( !status ) t = 0;
- else if ( ll ) t = ll, ll = 0;
- else if ( lr ) t = lr, lr = 0;
- else t = list_new( L0, newstr( "1" ) );
-
- if ( ll ) list_free( ll );
- if ( lr ) list_free( lr );
- return t;
-}
-
-
-/*
- * compile_foreach() - compile the "for x in y" statement
- *
- * Compile_foreach() resets the given variable name to each specified
- * value, executing the commands enclosed in braces for each iteration.
- *
- * parse->string index variable
- * parse->left variable values
- * parse->right rule to compile
- */
-
-LIST * compile_foreach( PARSE * parse, FRAME * frame )
-{
- LIST * nv = parse_evaluate( parse->left, frame );
- LIST * l;
- SETTINGS * s = 0;
-
- if ( parse->num )
- {
- s = addsettings( s, VAR_SET, parse->string, L0 );
- pushsettings( s );
- }
-
- /* Call var_set to reset $(parse->string) for each val. */
-
- for ( l = nv; l; l = list_next( l ) )
- {
- LIST * val = list_new( L0, copystr( l->string ) );
- var_set( parse->string, val, VAR_SET );
- list_free( parse_evaluate( parse->right, frame ) );
- }
-
- if ( parse->num )
- {
- popsettings( s );
- freesettings( s );
- }
-
- list_free( nv );
-
- return L0;
-}
-
-/*
- * compile_if() - compile 'if' rule
- *
- * parse->left condition tree
- * parse->right then tree
- * parse->third else tree
- */
-
-LIST * compile_if( PARSE * p, FRAME * frame )
-{
- LIST * l = parse_evaluate( p->left, frame );
- if ( l )
- {
- list_free( l );
- return parse_evaluate( p->right, frame );
- }
- return parse_evaluate( p->third, frame );
-}
-
-
-LIST * compile_while( PARSE * p, FRAME * frame )
-{
- LIST * r = 0;
- LIST * l;
- while ( ( l = parse_evaluate( p->left, frame ) ) )
- {
- list_free( l );
- if ( r ) list_free( r );
- r = parse_evaluate( p->right, frame );
- }
- return r;
-}
-
-
-/*
- * compile_include() - support for 'include' - call include() on file
- *
- * parse->left list of files to include (can only do 1)
- */
-
-LIST * compile_include( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "include", frame);
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->string );
-
- /* 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.
- */
-
- /* Bind the include file under the influence of */
- /* "on-target" variables. Though they are targets, */
- /* include files are not built with make(). */
-
- pushsettings( 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. */
- t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
-
- parse_file( t->boundname, frame );
- }
-
- list_free( nt );
-
- return L0;
-}
-
-static LIST* evaluate_in_module ( char* module_name, PARSE * p, FRAME* frame)
-{
- LIST* result;
-
- module_t* outer_module = frame->module;
- frame->module = module_name ? bindmodule( module_name ) : root_module();
-
- if ( outer_module != frame->module )
- {
- exit_module( outer_module );
- enter_module( frame->module );
- }
-
- result = parse_evaluate( p, frame );
-
- if ( outer_module != frame->module )
- {
- exit_module( frame->module );
- enter_module( outer_module );
- frame->module = outer_module;
- }
-
- return result;
-}
-
-
-LIST * compile_module( PARSE * p, FRAME * frame )
-{
- /* Here we are entering a module declaration block. */
- LIST * module_name = parse_evaluate( p->left, frame );
- LIST * result = evaluate_in_module( module_name ? module_name->string : 0,
- p->right, frame );
- list_free( module_name );
- return result;
-}
-
-
-LIST * compile_class( PARSE * p, FRAME * frame )
-{
- /** Todo: check for empty class name.
- Check for class redeclaration. */
-
- char * class_module = 0;
-
- LIST * name = parse_evaluate( p->left->right, frame );
- LIST * bases = 0;
-
- if ( p->left->left )
- bases = parse_evaluate( p->left->left->right, frame );
-
- class_module = make_class_module( name, bases, frame );
- evaluate_in_module( class_module, p->right, frame );
-
- return L0;
-}
-
-
-/*
- * compile_list() - expand and return a list.
- *
- * parse->string - character string to expand.
- */
-
-LIST * compile_list( PARSE * parse, FRAME * frame )
-{
- /* s is a copyable string */
- char * s = parse->string;
- return var_expand( L0, s, s + strlen( s ), frame->args, 1 );
-}
-
-
-/*
- * compile_local() - declare (and set) local variables.
- *
- * parse->left list of variables
- * parse->right list of values
- * parse->third rules to execute
- */
-
-LIST * compile_local( PARSE * parse, FRAME * frame )
-{
- LIST * l;
- SETTINGS * s = 0;
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * result;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "local", frame );
- list_print( nt );
- printf( " = " );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Initial value is ns. */
- for ( l = nt; l; l = list_next( l ) )
- s = addsettings( s, VAR_SET, l->string, list_copy( (LIST *)0, ns ) );
-
- list_free( ns );
- list_free( nt );
-
- /* Note that callees of the current context get this "local" variable,
- * making it not so much local as layered.
- */
-
- pushsettings( s );
- result = parse_evaluate( parse->third, frame );
- popsettings( s );
-
- freesettings( s );
-
- return result;
-}
-
-
-/*
- * compile_null() - do nothing -- a stub for parsing.
- */
-
-LIST * compile_null( PARSE * parse, FRAME * frame )
-{
- return L0;
-}
-
-
-/*
- * compile_on() - run rule under influence of on-target variables
- *
- * parse->left list of files to include (can only do 1).
- * parse->right rule to run.
- *
- * EXPERIMENTAL!
- */
-
-LIST * compile_on( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "on", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- if ( nt )
- {
- TARGET * t = bindtarget( nt->string );
- pushsettings( t->settings );
- result = parse_evaluate( parse->right, frame );
- popsettings( t->settings );
- }
-
- list_free( nt );
-
- return result;
-}
-
-
-/*
- * compile_rule() - compile a single user defined rule.
- *
- * parse->string name of user defined rule.
- * parse->left parameters (list of lists) to rule, recursing left.
- *
- * Wrapped around evaluate_rule() so that headers() can share it.
- */
-
-LIST * compile_rule( PARSE * parse, FRAME * frame )
-{
- FRAME inner[ 1 ];
- LIST * result;
- PARSE * p;
-
- /* Build up the list of arg lists. */
- 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(), below. */
- inner->procedure = parse;
- /* Special-case LOL of length 1 where the first list is totally empty.
- This is created when calling functions with no parameters, due to
- the way jam grammar is written. This is OK when one jam function
- calls another, but really not good when Jam function calls Python. */
- if ( parse->left->left == NULL && parse->left->right->func == compile_null)
- ;
- else
- for ( p = parse->left; p; p = p->left )
- lol_add( inner->args, parse_evaluate( p->right, frame ) );
-
- /* And invoke the rule. */
- result = evaluate_rule( parse->string, inner );
- frame_free( inner );
- return result;
-}
-
-
-static void argument_error( char * message, RULE * rule, FRAME * frame, LIST* arg )
-{
- LOL * actual = frame->args;
- assert( frame->procedure != 0 );
- backtrace_line( frame->prev );
- printf( "*** argument error\n* rule %s ( ", frame->rulename );
- lol_print( rule->arguments->data );
- printf( " )\n* called with: ( " );
- lol_print( actual );
- printf( " )\n* %s %s\n", message, arg ? arg->string : "" );
- print_source_line( rule->procedure );
- printf( "see definition of rule '%s' being called\n", rule->name );
- backtrace( frame->prev );
- exit( 1 );
-}
-
-
-/* Define delimiters for type check elements in argument lists (and return type
- * specifications, eventually).
- */
-# define TYPE_OPEN_DELIM '['
-# define TYPE_CLOSE_DELIM ']'
-
-/*
- * is_type_name() - true iff the given string represents a type check
- * specification.
- */
-
-static int is_type_name( char * s )
-{
- return ( s[ 0 ] == TYPE_OPEN_DELIM ) &&
- ( s[ strlen( s ) - 1 ] == TYPE_CLOSE_DELIM );
-}
-
-
-/*
- * arg_modifier - if the next element of formal is a single character, return
- * that; return 0 otherwise. Used to extract "*+?" modifiers * from argument
- * lists.
- */
-
-static char arg_modifier( LIST * formal )
-{
- if ( formal->next )
- {
- char * next = formal->next->string;
- if ( next && ( next[ 0 ] != 0 ) && ( next[ 1 ] == 0 ) )
- return next[ 0 ];
- }
- return 0;
-}
-
-
-/*
- * type_check() - checks that each element of values satisfies the requirements
- * of type_name.
- *
- * caller - the frame of the rule calling the rule whose arguments are
- * being checked
- *
- * called - the rule being called
- *
- * arg_name - a list element containing the name of the argument being
- * checked
- */
-
-static void type_check
-(
- char * type_name,
- LIST * values,
- FRAME * caller,
- RULE * called,
- LIST * arg_name
-)
-{
- static module_t * typecheck = 0;
-
- /* If nothing to check, bail now. */
- if ( !values || !type_name )
- return;
-
- if ( !typecheck )
- typecheck = bindmodule( ".typecheck" );
-
- /* If the checking rule can not be found, also bail. */
- {
- RULE checker_, *checker = &checker_;
-
- checker->name = type_name;
- if ( !typecheck->rules || !hashcheck( typecheck->rules, (HASHDATA * *)&checker ) )
- return;
- }
-
- exit_module( caller->module );
-
- while ( values != 0 )
- {
- 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;
-
- enter_module( typecheck );
- /* Prepare the argument list */
- lol_add( frame->args, list_new( L0, values->string ) );
- error = evaluate_rule( type_name, frame );
-
- exit_module( typecheck );
-
- if ( error )
- argument_error( error->string, called, caller, arg_name );
-
- frame_free( frame );
- values = values->next;
- }
-
- enter_module( caller->module );
-}
-
-/*
- * collect_arguments() - local argument checking and collection
- */
-static SETTINGS *
-collect_arguments( RULE* rule, FRAME* frame )
-{
- SETTINGS *locals = 0;
-
- LOL * all_actual = frame->args;
- LOL * all_formal = rule->arguments ? rule->arguments->data : 0;
- if ( all_formal ) /* Nothing to set; nothing to check */
- {
- int max = all_formal->count > all_actual->count
- ? all_formal->count
- : all_actual->count;
-
- int n;
- for ( n = 0; n < max ; ++n )
- {
- LIST *actual = lol_get( all_actual, n );
- char *type_name = 0;
-
- LIST *formal;
- for ( formal = lol_get( all_formal, n ); formal; formal = formal->next )
- {
- char* name = formal->string;
-
- if ( is_type_name(name) )
- {
- if ( type_name )
- argument_error( "missing argument name before type name:", rule, frame, formal );
-
- if ( !formal->next )
- argument_error( "missing argument name after type name:", rule, frame, formal );
-
- type_name = formal->string;
- }
- else
- {
- LIST* value = 0;
- char modifier;
- LIST* arg_name = formal; /* hold the argument name for type checking */
- int multiple = 0;
-
- /* Stop now if a variable number of arguments are specified */
- if ( name[0] == '*' && name[1] == 0 )
- return locals;
-
- modifier = arg_modifier( formal );
-
- if ( !actual && modifier != '?' && modifier != '*' )
- argument_error( "missing argument", rule, frame, formal );
-
- switch ( modifier )
- {
- case '+':
- case '*':
- value = list_copy( 0, actual );
- multiple = 1;
- actual = 0;
- /* skip an extra element for the modifier */
- formal = formal->next;
- break;
- case '?':
- /* skip an extra element for the modifier */
- formal = formal->next;
- /* fall through */
- default:
- if ( actual ) /* in case actual is missing */
- {
- value = list_new( 0, actual->string );
- actual = actual->next;
- }
- }
-
- locals = addsettings(locals, VAR_SET, name, value);
- locals->multiple = multiple;
- type_check( type_name, value, frame, rule, arg_name );
- type_name = 0;
- }
- }
-
- if ( actual )
- {
- argument_error( "extra argument", rule, frame, actual );
- }
- }
- }
- return locals;
-}
-
-RULE *
-enter_rule( char *rulename, module_t *target_module );
-
-#ifdef HAVE_PYTHON
-
-static int python_instance_number = 0;
-
-
-/* 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.
-
- The result value is newstr-ed. */
-char *python_to_string(PyObject* value)
-{
- if (PyString_Check(value))
- {
- return newstr(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 newstr(PyString_AsString(value2));
- }
- Py_DECREF(value2);
- }
- }
- return 0;
- }
-}
-
-static LIST*
-call_python_function(RULE* r, FRAME* frame)
-{
- LIST * result = 0;
- PyObject * arguments = 0;
- PyObject * kw = NULL;
- int i ;
- PyObject * py_result;
-
- if (r->arguments)
- {
- SETTINGS * args;
-
- arguments = PyTuple_New(0);
- kw = PyDict_New();
-
- for (args = collect_arguments(r, frame); args; args = args->next)
- {
- PyObject *key = PyString_FromString(args->symbol);
- PyObject *value = 0;
- if (args->multiple)
- value = list_to_python(args->value);
- else {
- if (args->value)
- value = PyString_FromString(args->value->string);
- }
-
- if (value)
- PyDict_SetItem(kw, key, value);
- Py_DECREF(key);
- Py_XDECREF(value);
- }
- }
- else
- {
- arguments = PyTuple_New( frame->args->count );
- for ( i = 0; i < frame->args->count; ++i )
- {
- PyObject * arg = PyList_New(0);
- LIST* l = lol_get( frame->args, i);
-
- for ( ; l; l = l->next )
- {
- PyObject * v = PyString_FromString(l->string);
- PyList_Append( arg, v );
- Py_DECREF(v);
- }
- /* Steals reference to 'arg' */
- PyTuple_SetItem( arguments, i, arg );
- }
- }
-
- frame_before_python_call = frame;
- py_result = PyObject_Call( r->python_function, arguments, kw );
- Py_DECREF(arguments);
- Py_XDECREF(kw);
- if ( py_result != NULL )
- {
- if ( PyList_Check( py_result ) )
- {
- int size = PyList_Size( py_result );
- int i;
- for ( i = 0; i < size; ++i )
- {
- PyObject * item = PyList_GetItem( py_result, i );
- char *s = python_to_string (item);
- if (!s) {
- fprintf( stderr, "Non-string object returned by Python call.\n" );
- } else {
- result = list_new (result, s);
- }
- }
- }
- else if ( py_result == Py_None )
- {
- result = L0;
- }
- else
- {
- char *s = python_to_string(py_result);
- if (s)
- result = list_new(0, 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;
- }
-
- Py_DECREF( py_result );
- }
- else
- {
- PyErr_Print();
- fprintf(stderr,"Call failed\n");
- }
-
- return result;
-}
-
-
-module_t * python_module()
-{
- static module_t * python = 0;
- if ( !python )
- python = bindmodule("__python__");
- return python;
-}
-
-#endif
-
-
-/*
* evaluate_rule() - execute a rule invocation.
*/
LIST *
evaluate_rule(
- char * rulename,
- FRAME * frame )
+ OBJECT * rulename,
+ FRAME * frame )
{
LIST * result = L0;
RULE * rule;
profile_frame prof[1];
module_t * prev_module = frame->module;
- LIST * l;
- {
- LOL arg_context_, * arg_context = &arg_context_;
- if ( !frame->prev )
- lol_init(arg_context);
- else
- arg_context = frame->prev->args;
- l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 );
- }
-
- if ( !l )
- {
- backtrace_line( frame->prev );
- printf( "warning: rulename %s expands to empty string\n", rulename );
- backtrace( frame->prev );
- return result;
- }
-
- rulename = l->string;
- rule = bindrule( l->string, frame->module );
-
-#ifdef HAVE_PYTHON
- if ( rule->python_function )
- {
- /* The below messing with modules is due to the way modules are
- * implemented in Jam. Suppose we are in module M1 now. The global
- * variable map actually holds 'M1' variables, and M1->variables hold
- * global variables.
- *
- * If we call Python right away, Python calls back Jam and then Jam
- * does 'module M1 { }' then Jam will try to swap the current global
- * variables with M1->variables. The result will be that global
- * variables map will hold global variables, and any variable settings
- * we do will go to the global module, not M1.
- *
- * By restoring basic state, where the global variable map holds global
- * variable, we make sure any future 'module M1' entry will work OK.
- */
-
- LIST * result;
- module_t * m = python_module();
-
- frame->module = m;
-
- exit_module( prev_module );
- enter_module( m );
-
- result = call_python_function( rule, frame );
-
- exit_module( m );
- enter_module ( prev_module );
-
- return result;
- }
-#endif
-
- /* Drop the rule name. */
- l = list_pop_front( l );
-
- /* Tack the rest of the expansion onto the front of the first argument. */
- frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) );
+ 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 && strcmp( rulename, rule->procedure->rulename ) )
+ && rule->procedure != 0 && !object_equal( rulename, function_rulename( rule->procedure ) ) )
{
char buf[256] = "";
- strncat( buf, rule->module->name, sizeof( buf ) - 1 );
- strncat( buf, rule->name, sizeof( buf ) - 1 );
+ if ( rule->module->name )
+ {
+ strncat( buf, object_str( rule->module->name ), sizeof( buf ) - 1 );
+ strncat( buf, ".", sizeof( buf ) - 1 );
+ }
+ strncat( buf, object_str( rule->name ), sizeof( buf ) - 1 );
debug_compile( 1, buf, frame );
}
else
{
- debug_compile( 1, rulename, frame );
+ debug_compile( 1, object_str( rulename ), frame );
}
lol_print( frame->args );
@@ -1024,26 +159,29 @@ evaluate_rule(
{
/* Propagate current module to nested rule invocations. */
frame->module = rule->module;
-
- /* Swap variables. */
- exit_module( prev_module );
- enter_module( rule->module );
}
/* Record current rule name in frame. */
if ( rule->procedure )
{
- frame->rulename = rulename;
+ frame->rulename = object_str( rulename );
/* And enter record profile info. */
if ( DEBUG_PROFILE )
- profile_enter( rule->procedure->rulename, prof );
+ profile_enter( function_rulename( rule->procedure ), prof );
}
/* Check traditional targets $(<) and sources $(>). */
if ( !rule->actions && !rule->procedure )
{
backtrace_line( frame->prev );
- printf( "rule %s unknown in module %s\n", rule->name, frame->module->name );
+ 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 );
}
@@ -1063,6 +201,7 @@ evaluate_rule(
action->rule = rule;
action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) );
action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) );
+ action->refs = 1;
/* 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
@@ -1109,30 +248,21 @@ evaluate_rule(
/* Append this action to the actions of each target. */
for ( t = action->targets; t; t = t->next )
t->target->actions = actionlist( t->target->actions, action );
+
+ action_free( action );
}
/* Now recursively compile any parse tree associated with this rule.
- * parse_refer()/parse_free() call pair added to ensure rule not freed
+ * function_refer()/function_free() call pair added to ensure rule not freed
* during use.
*/
if ( rule->procedure )
{
- SETTINGS * local_args = collect_arguments( rule, frame );
- PARSE * parse = rule->procedure;
- parse_refer( parse );
-
- pushsettings( local_args );
- result = parse_evaluate( parse, frame );
- popsettings( local_args );
- freesettings( local_args );
+ FUNCTION * function = rule->procedure;
- parse_free( parse );
- }
-
- if ( frame->module != prev_module )
- {
- exit_module( frame->module );
- enter_module( prev_module );
+ function_refer( function );
+ result = function_run( function, frame, stack_global() );
+ function_free( function );
}
if ( DEBUG_PROFILE && rule->procedure )
@@ -1154,7 +284,7 @@ evaluate_rule(
* which might be implemented in Jam.
*/
-LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
+LIST * call_rule( OBJECT * rulename, FRAME * caller_frame, ... )
{
va_list va;
LIST * result;
@@ -1165,7 +295,6 @@ LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
inner->prev_user = caller_frame->module->user_module ?
caller_frame : caller_frame->prev_user;
inner->module = caller_frame->module;
- inner->procedure = 0;
va_start( va, caller_frame );
for ( ; ; )
@@ -1185,218 +314,12 @@ LIST * call_rule( char * rulename, FRAME * caller_frame, ... )
}
-/*
- * compile_rules() - compile a chain of rules
- *
- * parse->left single rule
- * parse->right more compile_rules() by right-recursion
- */
-
-LIST * compile_rules( PARSE * parse, FRAME * frame )
-{
- /* Ignore result from first statement; return the 2nd. */
- /* Optimize recursion on the right by looping. */
- do list_free( parse_evaluate( parse->left, frame ) );
- while ( ( parse = parse->right )->func == compile_rules );
- return parse_evaluate( parse, frame );
-}
-
-
-/*
- * assign_var_mode() - convert ASSIGN_XXX compilation flag into corresponding
- * VAR_XXX variable set flag.
- */
-
-static int assign_var_mode( int parsenum, char const * * tracetext )
-{
- char const * trace;
- int setflag;
- switch ( parsenum )
- {
- case ASSIGN_SET : setflag = VAR_SET ; trace = "=" ; break;
- case ASSIGN_APPEND : setflag = VAR_APPEND ; trace = "+="; break;
- case ASSIGN_DEFAULT: setflag = VAR_DEFAULT; trace = "?="; break;
- default: setflag = VAR_SET ; trace = "" ; break;
- }
- if ( tracetext )
- *tracetext = trace ;
- return setflag;
-}
-
-/*
- * compile_set() - compile the "set variable" statement
- *
- * parse->left variable names
- * parse->right variable values
- * parse->num ASSIGN_SET/APPEND/DEFAULT
- */
-
-LIST * compile_set( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->right, frame );
- LIST * l;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call var_set to set variable. var_set keeps ns, so need to copy it. */
- for ( l = nt; l; l = list_next( l ) )
- var_set( l->string, list_copy( L0, ns ), setflag );
- list_free( nt );
- return ns;
-}
-
-
-/*
- * compile_setcomp() - support for `rule` - save parse tree.
- *
- * parse->string rule name
- * parse->left rules for rule
- * parse->right optional list-of-lists describing arguments
- */
-
-LIST * compile_setcomp( PARSE * parse, FRAME * frame )
-{
- argument_list * arg_list = 0;
-
- /* Create new LOL describing argument requirements if supplied. */
- if ( parse->right )
- {
- PARSE * p;
- arg_list = args_new();
- for ( p = parse->right; p; p = p->left )
- lol_add( arg_list->data, parse_evaluate( p->right, frame ) );
- }
-
- new_rule_body( frame->module, parse->string, arg_list, parse->left, !parse->num );
- return L0;
-}
-
-
-/*
- * compile_setexec() - support for `actions` - save execution string.
- *
- * parse->string rule name
- * parse->string1 OS command string
- * parse->num flags
- * parse->left `bind` variables
- *
- * Note that the parse flags (as defined in compile.h) are transferred directly
- * to the rule flags (as defined in rules.h).
- */
-
-LIST * compile_setexec( PARSE * parse, FRAME * frame )
-{
- LIST * bindlist = parse_evaluate( parse->left, frame );
- new_rule_actions( frame->module, parse->string, parse->string1, bindlist, parse->num );
- return L0;
-}
-
-
-/*
- * compile_settings() - compile the "on =" (set variable on exec) statement.
- *
- * parse->left variable names
- * parse->right target name
- * parse->third variable value
- * parse->num ASSIGN_SET/APPEND
- */
-
-LIST * compile_settings( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * ns = parse_evaluate( parse->third, frame );
- LIST * targets = parse_evaluate( parse->right, frame );
- LIST * ts;
- char const * trace;
- int setflag = assign_var_mode( parse->num, &trace );
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "set", frame );
- list_print( nt );
- printf( " on " );
- list_print( targets );
- printf( " %s ", trace );
- list_print( ns );
- printf( "\n" );
- }
-
- /* Call addsettings() to save variable setting. addsettings() keeps ns, so
- * need to copy it. Pass append flag to addsettings().
- */
- for ( ts = targets; ts; ts = list_next( ts ) )
- {
- TARGET * t = bindtarget( ts->string );
- LIST * l;
-
- for ( l = nt; l; l = list_next( l ) )
- t->settings = addsettings( t->settings, setflag, l->string,
- list_copy( (LIST *)0, ns ) );
- }
-
- list_free( nt );
- list_free( targets );
- return ns;
-}
-
-
-/*
- * compile_switch() - compile 'switch' rule.
- *
- * parse->left switch value (only 1st used)
- * parse->right cases
- *
- * cases->left 1st case
- * cases->right next cases
- *
- * case->string argument to match
- * case->left parse tree to execute
- */
-
-LIST * compile_switch( PARSE * parse, FRAME * frame )
-{
- LIST * nt = parse_evaluate( parse->left, frame );
- LIST * result = 0;
-
- if ( DEBUG_COMPILE )
- {
- debug_compile( 0, "switch", frame );
- list_print( nt );
- printf( "\n" );
- }
-
- /* Step through cases. */
- for ( parse = parse->right; parse; parse = parse->right )
- {
- if ( !glob( parse->left->string, nt ? nt->string : "" ) )
- {
- /* Get & exec parse tree for this case. */
- parse = parse->left->left;
- result = parse_evaluate( parse, frame );
- break;
- }
- }
-
- list_free( nt );
- return result;
-}
-
/*
* debug_compile() - printf with indent to show rule expansion.
*/
-static void debug_compile( int which, char * s, FRAME * frame )
+static void debug_compile( int which, const char * s, FRAME * frame )
{
static int level = 0;
static char indent[36] = ">>>>|>>>>|>>>>|>>>>|>>>>|>>>>|>>>>|";
@@ -1405,7 +328,7 @@ static void debug_compile( int which, char * s, FRAME * frame )
{
int i;
- print_source_line( frame->procedure );
+ print_source_line( frame );
i = ( level + 1 ) * 2;
while ( i > 35 )
diff --git a/tools/build/v2/engine/compile.h b/tools/build/v2/engine/compile.h
index 7d5191f0e1..1c002d90fa 100644
--- a/tools/build/v2/engine/compile.h
+++ b/tools/build/v2/engine/compile.h
@@ -16,6 +16,7 @@
# include "frames.h"
# include "parse.h"
# include "regexp.h"
+# include "object.h"
/*
* compile.h - compile parsed jam statements
@@ -23,30 +24,10 @@
void compile_builtins();
-LIST *compile_append( PARSE *parse, FRAME *frame );
-LIST *compile_foreach( PARSE *parse, FRAME *frame );
-LIST *compile_if( PARSE *parse, FRAME *frame );
-LIST *compile_eval( PARSE *parse, FRAME *args );
-LIST *compile_include( PARSE *parse, FRAME *frame );
-LIST *compile_list( PARSE *parse, FRAME *frame );
-LIST *compile_local( PARSE *parse, FRAME *frame );
-LIST *compile_module( PARSE *parse, FRAME *frame );
-LIST *compile_class( PARSE *parse, FRAME *frame );
-LIST *compile_null( PARSE *parse, FRAME *frame );
-LIST *compile_on( PARSE *parse, FRAME *frame );
-LIST *compile_rule( PARSE *parse, FRAME *frame );
-LIST *compile_rules( PARSE *parse, FRAME *frame );
-LIST *compile_set( PARSE *parse, FRAME *frame );
-LIST *compile_setcomp( PARSE *parse, FRAME *frame );
-LIST *compile_setexec( PARSE *parse, FRAME *frame );
-LIST *compile_settings( PARSE *parse, FRAME *frame );
-LIST *compile_switch( PARSE *parse, FRAME *frame );
-LIST *compile_while( PARSE *parse, FRAME *frame );
-
-LIST *evaluate_rule( char *rulename, FRAME *frame );
-LIST *call_rule( char *rulename, FRAME* caller_frame, ...);
-
-regexp* regex_compile( const char* pattern );
+LIST *evaluate_rule( OBJECT * rulename, FRAME * frame );
+LIST *call_rule( OBJECT * rulename, FRAME * caller_frame, ...);
+
+regexp* regex_compile( OBJECT * pattern );
/* Flags for compile_set(), etc */
diff --git a/tools/build/v2/engine/constants.c b/tools/build/v2/engine/constants.c
new file mode 100644
index 0000000000..3ad534ed75
--- /dev/null
+++ b/tools/build/v2/engine/constants.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+# include "constants.h"
+# include "object.h"
+
+/*
+ * constants.c - constant objects
+ *
+ * External functions:
+ *
+ * constants_init() - initialize constants
+ * constants_done() - free constants
+ *
+ */
+
+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" );
+}
+
+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 );
+ object_free( constant_ok );
+ object_free( constant_true );
+ object_free( constant_name );
+ object_free( constant_bases );
+ object_free( constant_typecheck );
+ object_free( constant_builtin );
+ object_free( constant_HCACHEFILE );
+ object_free( constant_HCACHEMAXAGE );
+ object_free( constant_HDRSCAN );
+ object_free( constant_HDRRULE );
+ object_free( constant_BINDRULE );
+ object_free( constant_LOCATE );
+ object_free( constant_SEARCH );
+ object_free( constant_JAM_SEMAPHORE );
+ object_free( constant_TIMING_RULE );
+ object_free( constant_ACTION_RULE );
+ object_free( constant_JAMSHELL );
+ object_free( constant_TMPDIR );
+ object_free( constant_TMPNAME );
+ object_free( constant_TMPFILE );
+ object_free( constant_STDOUT );
+ object_free( constant_STDERR );
+ object_free( constant_JAMDATE );
+ object_free( constant_JAM_VERSION );
+ object_free( constant_JAMUNAME );
+ object_free( constant_ENVIRON );
+ object_free( constant_ARGV );
+ object_free( constant_all );
+ object_free( constant_PARALLELISM );
+ object_free( constant_KEEP_GOING );
+ object_free( constant_other );
+ object_free( constant_total );
+ object_free( constant_FILE_DIRSCAN );
+ object_free( constant_MAIN );
+ object_free( constant_MAIN_MAKE );
+ object_free( constant_MAKE_MAKE0 );
+ object_free( constant_MAKE_MAKE1 );
+ object_free( constant_MAKE_MAKE0SORT );
+ object_free( constant_BINDMODULE );
+ object_free( constant_IMPORT_MODULE );
+ object_free( constant_BUILTIN_GLOB_BACK );
+ object_free( constant_timestamp );
+ object_free( constant_python );
+ object_free( constant_python_interface );
+ object_free( constant_extra_pythonpath );
+ object_free( constant_MAIN_PYTHON );
+}
+
+OBJECT * constant_empty;
+OBJECT * constant_dot;
+OBJECT * constant_percent;
+OBJECT * constant_plus;
+OBJECT * constant_star;
+OBJECT * constant_question_mark;
+OBJECT * constant_ok;
+OBJECT * constant_true;
+OBJECT * constant_name;
+OBJECT * constant_bases;
+OBJECT * constant_typecheck;
+OBJECT * constant_builtin;
+OBJECT * constant_HCACHEFILE;
+OBJECT * constant_HCACHEMAXAGE;
+OBJECT * constant_HDRSCAN;
+OBJECT * constant_HDRRULE;
+OBJECT * constant_BINDRULE;
+OBJECT * constant_LOCATE;
+OBJECT * constant_SEARCH;
+OBJECT * constant_JAM_SEMAPHORE;
+OBJECT * constant_TIMING_RULE;
+OBJECT * constant_ACTION_RULE;
+OBJECT * constant_JAMSHELL;
+OBJECT * constant_TMPDIR;
+OBJECT * constant_TMPNAME;
+OBJECT * constant_TMPFILE;
+OBJECT * constant_STDOUT;
+OBJECT * constant_STDERR;
+OBJECT * constant_JAMDATE;
+OBJECT * constant_JAM_VERSION;
+OBJECT * constant_JAMUNAME;
+OBJECT * constant_ENVIRON;
+OBJECT * constant_ARGV;
+OBJECT * constant_all;
+OBJECT * constant_PARALLELISM;
+OBJECT * constant_KEEP_GOING;
+OBJECT * constant_other;
+OBJECT * constant_total;
+OBJECT * constant_FILE_DIRSCAN;
+OBJECT * constant_MAIN;
+OBJECT * constant_MAIN_MAKE;
+OBJECT * constant_MAKE_MAKE0;
+OBJECT * constant_MAKE_MAKE1;
+OBJECT * constant_MAKE_MAKE0SORT;
+OBJECT * constant_BINDMODULE;
+OBJECT * constant_IMPORT_MODULE;
+OBJECT * constant_BUILTIN_GLOB_BACK;
+OBJECT * constant_timestamp;
+OBJECT * constant_python;
+OBJECT * constant_python_interface;
+OBJECT * constant_extra_pythonpath;
+OBJECT * constant_MAIN_PYTHON;
diff --git a/tools/build/v2/engine/constants.h b/tools/build/v2/engine/constants.h
new file mode 100644
index 0000000000..2ec27e800f
--- /dev/null
+++ b/tools/build/v2/engine/constants.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * constants.h - constant objects
+ */
+
+#ifndef BOOST_JAM_CONSTANTS_H
+#define BOOST_JAM_CONSTANTS_H
+
+#include "object.h"
+
+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" */
+
+#endif
diff --git a/tools/build/v2/engine/debug.c b/tools/build/v2/engine/debug.c
index 7290555a74..827356bb83 100644
--- a/tools/build/v2/engine/debug.c
+++ b/tools/build/v2/engine/debug.c
@@ -14,34 +14,41 @@
static profile_frame * profile_stack = 0;
static struct hash * profile_hash = 0;
-static profile_info profile_other = { "[OTHER]", 0, 0, 0, 0, 0 };
-static profile_info profile_total = { "[TOTAL]", 0, 0, 0, 0, 0 };
+static profile_info profile_other = { 0, 0, 0, 0, 0, 0 };
+static profile_info profile_total = { 0, 0, 0, 0, 0, 0 };
-profile_frame * profile_init( char * rulename, profile_frame * frame )
+profile_frame * profile_init( OBJECT * rulename, profile_frame * frame )
{
if ( DEBUG_PROFILE ) profile_enter( rulename, frame );
return frame;
}
-void profile_enter( char * rulename, profile_frame * frame )
+void profile_enter( OBJECT * rulename, profile_frame * frame )
{
if ( DEBUG_PROFILE )
{
clock_t start = clock();
- profile_info info;
- profile_info * p = &info;
-
- if ( !rulename ) p = &profile_other;
+ profile_info * p;
if ( !profile_hash && rulename )
profile_hash = hashinit( sizeof( profile_info ), "profile" );
- info.name = rulename;
-
- if ( rulename && hashenter( profile_hash, (HASHDATA * *)&p ) )
- p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ if ( rulename )
+ {
+ int found;
+ p = (profile_info *)hash_insert( profile_hash, rulename, &found );
+ if ( !found )
+ {
+ p->name = rulename;
+ p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+ }
+ }
+ else
+ {
+ p = &profile_other;
+ }
++p->num_entries;
++p->stack_count;
@@ -115,7 +122,7 @@ static void dump_profile_entry( void * p_, void * ignored )
profile_total.memory += p->memory;
}
printf( "%10ld %12.6f %12.6f %12.8f %10ld %10ld %s\n", p->num_entries,
- cumulative, net, q, p->memory, mem_each, p->name );
+ cumulative, net, q, p->memory, mem_each, object_str( p->name ) );
}
@@ -126,7 +133,9 @@ void profile_dump()
printf( "%10s %12s %12s %12s %10s %10s %s\n", "--count--", "--gross--",
"--net--", "--each--", "--mem--", "--each--", "--name--" );
hashenumerate( profile_hash, dump_profile_entry, 0 );
+ profile_other.name = constant_other;
dump_profile_entry( &profile_other, 0 );
+ profile_total.name = constant_total;
dump_profile_entry( &profile_total, (void *)1 );
}
}
diff --git a/tools/build/v2/engine/debug.h b/tools/build/v2/engine/debug.h
index 115a88735b..baad262a00 100644
--- a/tools/build/v2/engine/debug.h
+++ b/tools/build/v2/engine/debug.h
@@ -6,6 +6,7 @@
#ifndef BJAM_DEBUG_H
#define BJAM_DEBUG_H
+#include "constants.h"
#include "jam.h"
#include <time.h>
@@ -13,7 +14,7 @@
struct profile_info
{
/* name of rule being called */
- char* name;
+ OBJECT * name;
/* cumulative time spent in rule */
clock_t cumulative;
/* time spent in rule proper */
@@ -42,13 +43,13 @@ struct profile_frame
};
typedef struct profile_frame profile_frame;
-profile_frame * profile_init( char * rulename, profile_frame * frame );
-void profile_enter( char* rulename, profile_frame * frame );
+profile_frame * profile_init( OBJECT * rulename, profile_frame * frame );
+void profile_enter( OBJECT * rulename, profile_frame * frame );
void profile_memory( long mem );
void profile_exit( profile_frame * frame );
void profile_dump();
-#define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( #scope, &PROF_ ## scope )
+#define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( constant_ ## scope, &PROF_ ## scope )
#define PROFILE_EXIT( scope ) profile_exit( PROF_ ## scope ## _p )
#endif
diff --git a/tools/build/v2/engine/execcmd.h b/tools/build/v2/engine/execcmd.h
index 67f2b839c6..9d3cff35b2 100644
--- a/tools/build/v2/engine/execcmd.h
+++ b/tools/build/v2/engine/execcmd.h
@@ -28,16 +28,18 @@ typedef struct timing_info
void exec_cmd
(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
+ const char * string,
+ void (* func)( void * closure, int status, timing_info *, const char *, const char * ),
void * closure,
LIST * shell,
- char * action,
- char * target
+ const char * action,
+ const char * target
);
int exec_wait();
+void exec_done( void );
+
#define EXEC_CMD_OK 0
#define EXEC_CMD_FAIL 1
#define EXEC_CMD_INTR 2
diff --git a/tools/build/v2/engine/execmac.c b/tools/build/v2/engine/execmac.c
deleted file mode 100644
index 2ddddedd15..0000000000
--- a/tools/build/v2/engine/execmac.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-#include "jam.h"
-#include "lists.h"
-#include "execcmd.h"
-#include <errno.h>
-
-#ifdef OS_MAC
-
-/*
- * execunix.c - execute a shell script on UNIX
- *
- * If $(JAMSHELL) is defined, uses that to formulate execvp().
- * The default is:
- *
- * /bin/sh -c %
- *
- * 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 - 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
- */
-
-
-/*
- * exec_cmd() - launch an async command execution.
- */
-
-void exec_cmd
-(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
- void * closure,
- LIST * shell
-)
-{
- printf( "%s", string );
- (*func)( closure, EXEC_CMD_OK );
-}
-
-/*
- * exec_wait() - wait and drive at most one execution completion.
- */
-
-int exec_wait()
-{
- return 0;
-}
-
-#endif /* OS_MAC */
diff --git a/tools/build/v2/engine/execnt.c b/tools/build/v2/engine/execnt.c
index 7642045180..f34b378549 100644
--- a/tools/build/v2/engine/execnt.c
+++ b/tools/build/v2/engine/execnt.c
@@ -65,13 +65,13 @@
int maxline();
/* delete and argv list */
-static void free_argv(char**);
+static void free_argv(const char * *);
/* Convert a command string into arguments for spawnvp. */
-static char** string_to_args(const char*);
+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(char*);
+long can_spawn(const char*);
/* Add two 64-bit unsigned numbers, h1l1 and h2l2 */
static FILETIME add_64(
unsigned long h1, unsigned long l1,
@@ -135,7 +135,7 @@ static struct
int exit_reason; /* reason why a command completed */
/* Function called when the command completes. */
- void (* func)( void * closure, int status, timing_info *, char *, char * );
+ void (* func)( void * closure, int status, timing_info *, const char *, const char * );
/* Opaque data passed back to the 'func' callback called when the command
* completes.
@@ -184,7 +184,7 @@ void execnt_unit_test()
/* Work around vc6 bug; it doesn't like escaped string
* literals inside assert
*/
- char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
+ const char * * argv = string_to_args(" \"g++\" -c -I\"Foobar\"" );
char const expected[] = "-c -I\"Foobar\"";
assert( !strcmp( argv[ 0 ], "g++" ) );
@@ -201,26 +201,26 @@ void execnt_unit_test()
void exec_cmd
(
- char * command,
- void (* func)( void * closure, int status, timing_info *, char * invoked_command, char * command_output ),
- void * closure,
- LIST * shell,
- char * action,
- char * target
+ 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
)
{
int slot;
int raw_cmd = 0 ;
- char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
- char * * argv = argv_static;
+ const char * argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
+ const char * * argv = argv_static;
char * p;
- char * command_orig = command;
+ 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.
*/
- if ( shell && !strcmp( shell->string, "%" ) && !list_next( shell ) )
+ if ( !list_empty( shell ) && !strcmp( object_str( list_front( shell ) ), "%" ) && list_next( list_begin( shell ) ) == list_end( shell ) )
{
raw_cmd = 1;
shell = 0;
@@ -290,8 +290,8 @@ void exec_cmd
if ( DEBUG_EXECCMD )
{
- if ( shell )
- printf( "using user-specified shell: %s", shell->string );
+ if ( !list_empty( shell ) )
+ printf( "using user-specified shell: %s", object_str( list_front( shell ) ) );
else
printf( "Executing through .bat file\n" );
}
@@ -305,16 +305,17 @@ void exec_cmd
int i;
char jobno[ 4 ];
int gotpercent = 0;
+ LISTITER shell_iter = list_begin( shell ), shell_end = list_end( shell );
sprintf( jobno, "%d", slot + 1 );
- for ( i = 0; shell && ( i < MAXARGC ); ++i, shell = list_next( shell ) )
+ for ( i = 0; shell_iter != shell_end && ( i < MAXARGC ); ++i, shell_iter = list_next( shell_iter ) )
{
- switch ( shell->string[ 0 ] )
+ switch ( object_str( list_item( shell_iter ) )[ 0 ] )
{
case '%': argv[ i ] = command; ++gotpercent; break;
case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = shell->string;
+ default : argv[ i ] = object_str( list_item( shell_iter ) );
}
if ( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[ i ] );
@@ -425,7 +426,7 @@ void exec_cmd
/* Put together the command we run. */
{
- char * * argp = argv;
+ const char * * argp = argv;
string_new( &cmd );
string_copy( &cmd, *(argp++) );
while ( *argp )
@@ -577,10 +578,10 @@ int exec_wait()
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-static void free_argv( char * * args )
+static void free_argv( const char * * args )
{
- BJAM_FREE( args[ 0 ] );
- BJAM_FREE( args );
+ BJAM_FREE( (void *)args[ 0 ] );
+ BJAM_FREE( (void *)args );
}
@@ -613,14 +614,14 @@ int maxline()
* New strategy: break the string in at most one place.
*/
-static char * * string_to_args( char const * string )
+static const char * * string_to_args( char const * string )
{
int src_len;
int in_quote;
char * line;
char const * src;
char * dst;
- char * * argv;
+ const char * * argv;
/* Drop leading and trailing whitespace if any. */
while ( isspace( *string ) )
@@ -640,7 +641,7 @@ static char * * string_to_args( char const * string )
* element 1: stores the command-line arguments to the executable
* element 2: NULL terminator
*/
- argv = (char * *)BJAM_MALLOC( 3 * sizeof( char * ) );
+ argv = (const char * *)BJAM_MALLOC( 3 * sizeof( const char * ) );
if ( !argv )
{
BJAM_FREE( line );
@@ -697,9 +698,9 @@ static void onintr( int disp )
* Otherwise, return zero.
*/
-long can_spawn( char * command )
+long can_spawn( const char * command )
{
- char * p;
+ const char * p;
char inquote = 0;
/* Move to the first non-whitespace. */
@@ -1293,4 +1294,10 @@ static void close_alert( HANDLE process )
}
}
+
+void exec_done( void )
+{
+}
+
+
#endif /* USE_EXECNT */
diff --git a/tools/build/v2/engine/execunix.c b/tools/build/v2/engine/execunix.c
index ef9dba0037..147d051cd5 100644
--- a/tools/build/v2/engine/execunix.c
+++ b/tools/build/v2/engine/execunix.c
@@ -88,7 +88,7 @@ static struct
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*, char *, char * );
+ 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}};
@@ -110,12 +110,12 @@ void onintr( int disp )
void exec_cmd
(
- char * string,
- void (*func)( void *closure, int status, timing_info*, char *, char * ),
+ const char * string,
+ void (*func)( void *closure, int status, timing_info*, const char *, const char * ),
void * closure,
LIST * shell,
- char * action,
- char * target
+ const char * action,
+ const char * target
)
{
static int initialized = 0;
@@ -123,7 +123,7 @@ void exec_cmd
int err[2];
int slot;
int len;
- char * argv[ MAXARGC + 1 ]; /* +1 for NULL */
+ 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 )
@@ -139,21 +139,22 @@ void exec_cmd
/* Forumulate argv. If shell was defined, be prepared for % and ! subs.
* Otherwise, use stock /bin/sh on unix or cmd.exe on NT.
*/
- if ( shell )
+ 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 );
- for ( i = 0; shell && i < MAXARGC; ++i, shell = list_next( shell ) )
+ for ( i = 0; iter != end && i < MAXARGC; ++i, iter = list_next( iter ) )
{
- switch ( shell->string[0] )
+ switch ( object_str( list_item( iter ) )[0] )
{
case '%': argv[ i ] = string; ++gotpercent; break;
case '!': argv[ i ] = jobno; break;
- default : argv[ i ] = shell->string;
+ default : argv[ i ] = object_str( list_item( iter ) );
}
if ( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[ i ] );
@@ -242,7 +243,7 @@ void exec_cmd
setrlimit( RLIMIT_CPU, &r_limit );
}
setpgid( pid,pid );
- execvp( argv[0], argv );
+ execvp( argv[0], (char * *)argv );
perror( "execvp" );
_exit( 127 );
}
@@ -566,4 +567,15 @@ int exec_wait()
return 1;
}
+void exec_done( void )
+{
+ int i;
+ for( i = 0; i < MAXJOBS; ++i )
+ {
+ if( ! cmdtab[i].action ) break;
+ BJAM_FREE( cmdtab[i].action );
+ BJAM_FREE( cmdtab[i].target );
+ }
+}
+
# endif /* USE_EXECUNIX */
diff --git a/tools/build/v2/engine/execvms.c b/tools/build/v2/engine/execvms.c
deleted file mode 100644
index 729917d356..0000000000
--- a/tools/build/v2/engine/execvms.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-#include "jam.h"
-#include "lists.h"
-#include "execcmd.h"
-
-#ifdef OS_VMS
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <iodef.h>
-#include <ssdef.h>
-#include <descrip.h>
-#include <dvidef.h>
-#include <clidef.h>
-
-/*
- * execvms.c - execute a shell script, ala VMS.
- *
- * The approach is this:
- *
- * If the command is a single line, and shorter than WRTLEN (what we believe to
- * be the maximum line length), we just system() it.
- *
- * If the command is multi-line, or longer than WRTLEN, we write the command
- * block to a temp file, splitting long lines (using "-" at the end of the line
- * to indicate contiuation), and then source that temp file. We use special
- * logic to make sure we do not continue in the middle of a quoted string.
- *
- * 05/04/94 (seiwald) - async multiprocess interface; noop on VMS
- * 12/20/96 (seiwald) - rewritten to handle multi-line commands well
- * 01/14/96 (seiwald) - do not put -'s between "'s
- */
-
-#define WRTLEN 240
-
-#define MIN( a, b ) ((a) < (b) ? (a) : (b))
-
-/* 1 for the @ and 4 for the .com */
-
-char tempnambuf[ L_tmpnam + 1 + 4 ] = { 0 };
-
-
-void exec_cmd
-(
- char * string,
- void (* func)( void * closure, int status, timing_info *, char *, char * ),
- void * closure,
- LIST * shell,
- char * rule_name,
- char * target
-)
-{
- char * s;
- char * e;
- cahr * p;
- int rstat = EXEC_CMD_OK;
- int status;
-
- /* See if string is more than one line discounting leading/trailing white
- * space.
- */
- for ( s = string; *s && isspace( *s ); ++s );
-
- e = p = strchr( s, '\n' );
-
- while ( p && isspace( *p ) )
- ++p;
-
- /* If multi line or long, write to com file. Otherwise, exec directly. */
- if ( ( p && *p ) || ( e - s > WRTLEN ) )
- {
- FILE * f;
-
- /* Create temp file invocation "@sys$scratch:tempfile.com". */
- if ( !*tempnambuf )
- {
- tempnambuf[0] = '@';
- (void)tmpnam( tempnambuf + 1 );
- strcat( tempnambuf, ".com" );
- }
-
- /* Open tempfile. */
- if ( !( f = fopen( tempnambuf + 1, "w" ) ) )
- {
- printf( "can't open command file\n" );
- (*func)( closure, EXEC_CMD_FAIL );
- return;
- }
-
- /* For each line of the string. */
- while ( *string )
- {
- char * s = strchr( string, '\n' );
- int len = s ? s + 1 - string : strlen( string );
-
- fputc( '$', f );
-
- /* For each chunk of a line that needs to be split. */
- while ( len > 0 )
- {
- char * q = string;
- char * qe = string + MIN( len, WRTLEN );
- char * qq = q;
- int quote = 0;
-
- /* Look for matching "s. */
- for ( ; q < qe; ++q )
- if ( ( *q == '"' ) && ( quote = !quote ) )
- qq = q;
-
- /* Back up to opening quote, if in one. */
- if ( quote )
- q = qq;
-
- fwrite( string, ( q - string ), 1, f );
-
- len -= ( q - string );
- string = q;
-
- if ( len )
- {
- fputc( '-', f );
- fputc( '\n', f );
- }
- }
- }
-
- fclose( f );
-
- status = system( tempnambuf ) & 0x07;
-
- unlink( tempnambuf + 1 );
- }
- else
- {
- /* Execute single line command. Strip trailing newline before execing.
- */
- if ( e ) *e = 0;
- status = system( s ) & 0x07;
- }
-
- /* Fail for error or fatal error. OK on OK, warning or info exit. */
- if ( ( status == 2 ) || ( status == 4 ) )
- rstat = EXEC_CMD_FAIL;
-
- (*func)( closure, rstat );
-}
-
-
-int exec_wait()
-{
- return 0;
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/expand.c b/tools/build/v2/engine/expand.c
deleted file mode 100644
index d8e58827c6..0000000000
--- a/tools/build/v2/engine/expand.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-# include "jam.h"
-# include "lists.h"
-# include "variable.h"
-# include "expand.h"
-# include "pathsys.h"
-# include "newstr.h"
-# include <assert.h>
-# include <stdlib.h>
-# include <limits.h>
-
-# ifdef OS_CYGWIN
-# include <sys/cygwin.h>
-# include <windows.h>
-# endif
-
-/*
- * expand.c - expand a buffer, given variable values
- *
- * External routines:
- *
- * var_expand() - variable-expand input string into list of strings
- *
- * Internal routines:
- *
- * var_edit_parse() - parse : modifiers into PATHNAME structure.
- * var_edit_file() - copy input target name to output, modifying filename.
- * var_edit_shift() - do upshift/downshift mods.
- *
- * 01/25/94 (seiwald) - $(X)$(UNDEF) was expanding like plain $(X)
- * 04/13/94 (seiwald) - added shorthand L0 for null list pointer
- * 01/11/01 (seiwald) - added support for :E=emptyvalue, :J=joinval
- */
-
-typedef struct
-{
- PATHNAME f; /* :GDBSMR -- pieces */
- char parent; /* :P -- go to parent directory */
- char filemods; /* one of the above applied */
- char downshift; /* :L -- downshift result */
- char upshift; /* :U -- upshift result */
- char to_slashes; /* :T -- convert "\" to "/" */
- char to_windows; /* :W -- convert cygwin to native paths */
- PATHPART empty; /* :E -- default for empties */
- PATHPART join; /* :J -- join list with char */
-} VAR_EDITS ;
-
-static void var_edit_parse( char * mods, VAR_EDITS * edits );
-static void var_edit_file ( char * in, string * out, VAR_EDITS * edits );
-static void var_edit_shift( string * out, VAR_EDITS * edits );
-
-#define MAGIC_COLON '\001'
-#define MAGIC_LEFT '\002'
-#define MAGIC_RIGHT '\003'
-
-
-/*
- * var_expand() - variable-expand input string into list of strings.
- *
- * Would just copy input to output, performing variable expansion, except that
- * since variables can contain multiple values the result of variable expansion
- * may contain multiple values (a list). Properly performs "product" operations
- * that occur in "$(var1)xxx$(var2)" or even "$($(var2))".
- *
- * Returns a newly created list.
- */
-
-LIST * var_expand( LIST * l, char * in, char * end, LOL * lol, int cancopyin )
-{
- char out_buf[ MAXSYM ];
- string buf[ 1 ];
- string out1[ 1 ]; /* temporary buffer */
- size_t prefix_length;
- char * out;
- char * inp = in;
- char * ov; /* for temp copy of variable in outbuf */
- int depth;
-
- if ( DEBUG_VAREXP )
- printf( "expand '%.*s'\n", end - in, in );
-
- /* This gets a lot of cases: $(<) and $(>). */
- if
- (
- ( in[ 0 ] == '$' ) &&
- ( in[ 1 ] == '(' ) &&
- ( in[ 3 ] == ')' ) &&
- ( in[ 4 ] == '\0' )
- )
- {
- switch ( in[ 2 ] )
- {
- case '<': return list_copy( l, lol_get( lol, 0 ) );
- case '>': return list_copy( l, lol_get( lol, 1 ) );
-
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return list_copy( l, lol_get( lol, in[ 2 ] - '1' ) );
- }
- }
- else if ( in[0] == '$' && in[1] == '(' && in[2] == '1' && in[4] == ')' &&
- in[5] == '\0') {
-
- switch( in[3] )
- {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- return list_copy( l, lol_get( lol, in[3]-'0'+10-1 ) );
- }
- }
-
- /* Expand @() files, to single item plus accompanying file. */
- if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) && ( *( end - 1 ) == ')' ) )
- {
- /* We try the expansion until it fits within the propective output
- * buffer.
- */
- char * at_buf = 0;
- int at_size = MAXJPATH;
- int at_len = 0;
- do
- {
- BJAM_FREE( at_buf );
- at_buf = (char *)BJAM_MALLOC_ATOMIC( at_size + 1 );
- at_len = var_string( in, at_buf, at_size, lol );
- at_size *= 2;
- }
- while ( ( at_len < 0 ) && ( at_size < INT_MAX / 2 ) );
- /* Return the result as a single item list. */
- if ( at_len > 0 )
- {
- LIST * r;
- string_copy( buf, at_buf );
- r = list_new( l, newstr( buf->value ) );
- string_free( buf );
- BJAM_FREE( at_buf );
- return r;
- }
- BJAM_FREE( at_buf );
- }
-
- /* Just try simple copy of in to out. */
- while ( in < end )
- if ( ( *in++ == '$' ) && ( *in == '(' ) )
- goto expand;
-
- /* No variables expanded - just add copy of input string to list. */
-
- /* 'cancopyin' is an optimization: if the input was already a list item, we
- * can use copystr() to put it on the new list. Otherwise, we use the slower
- * newstr().
- */
- if ( cancopyin )
- return list_new( l, copystr( inp ) );
-
- {
- LIST * r;
- string_new( buf );
- string_append_range( buf, inp, end );
- r = list_new( l, newstr( buf->value ) );
- string_free( buf );
- return r;
- }
-
-expand:
- string_new( buf );
- string_append_range( buf, inp, in - 1 ); /* Copy the part before '$'. */
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^
- * in end
- * Output so far:
- *
- * stuff-in-outbuf $
- * ^ ^
- * out_buf out
- *
- *
- * We just copied the $ of $(...), so back up one on the output. We now find
- * the matching close paren, copying the variable and modifiers between the
- * $( and ) temporarily into out_buf, so that we can replace :'s with
- * MAGIC_COLON. This is necessary to avoid being confused by modifier values
- * that are variables containing :'s. Ugly.
- */
-
- depth = 1;
- inp = ++in; /* Skip over the '('. */
-
- while ( ( in < end ) && depth )
- {
- switch ( *in++ )
- {
- case '(': ++depth; break;
- case ')': --depth; break;
- }
- }
-
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^ ^
- * inp in end
- */
- prefix_length = buf->size;
- string_append_range( buf, inp, in - 1 );
-
- out = buf->value + prefix_length;
- for ( ov = out; ov < buf->value + buf->size; ++ov )
- {
- switch ( *ov )
- {
- case ':': *ov = MAGIC_COLON; break;
- case '[': *ov = MAGIC_LEFT ; break;
- case ']': *ov = MAGIC_RIGHT; break;
- }
- }
-
- /*
- * Input so far (ignore blanks):
- *
- * stuff-in-outbuf $(variable) remainder
- * ^ ^
- * in end
- * Output so far:
- *
- * stuff-in-outbuf variable
- * ^ ^ ^
- * out_buf out ov
- *
- * Later we will overwrite 'variable' in out_buf, but we will be done with
- * it by then. 'variable' may be a multi-element list, so may each value for
- * '$(variable element)', and so may 'remainder'. Thus we produce a product
- * of three lists.
- */
- {
- LIST * variables = 0;
- LIST * remainder = 0;
- LIST * vars;
-
- /* Recursively expand variable name & rest of input. */
- if ( out < ov ) variables = var_expand( L0, out, ov, lol, 0 );
- if ( in < end ) remainder = var_expand( L0, in, end, lol, 0 );
-
- /* Now produce the result chain. */
-
- /* For each variable name. */
- for ( vars = variables; vars; vars = list_next( vars ) )
- {
- LIST * value = 0;
- LIST * evalue = 0;
- char * colon;
- char * bracket;
- string variable[1];
- char * varname;
- int sub1 = 0;
- int sub2 = -1;
- VAR_EDITS edits;
-
- /* Look for a : modifier in the variable name. Must copy into
- * varname so we can modify it.
- */
- string_copy( variable, vars->string );
- varname = variable->value;
-
- if ( ( colon = strchr( varname, MAGIC_COLON ) ) )
- {
- string_truncate( variable, colon - varname );
- var_edit_parse( colon + 1, &edits );
- }
-
- /* Look for [x-y] subscripting. sub1 and sub2 are x and y. */
- if ( ( bracket = strchr( varname, MAGIC_LEFT ) ) )
- {
- /* Make all syntax errors in [] subscripting result in the same
- * behavior: silenty return an empty expansion (by setting sub2
- * = 0). Brute force parsing; May get moved into yacc someday.
- */
-
- char * s = bracket + 1;
-
- string_truncate( variable, bracket - varname );
-
- do /* so we can use "break" */
- {
- /* Allow negative indexes. */
- if ( !isdigit( *s ) && ( *s != '-' ) )
- {
- sub2 = 0;
- break;
- }
- sub1 = atoi( s );
-
- /* Skip over the first symbol, which is either a digit or dash. */
- ++s;
- while ( isdigit( *s ) ) ++s;
-
- if ( *s == MAGIC_RIGHT )
- {
- sub2 = sub1;
- break;
- }
-
- if ( *s != '-' )
- {
- sub2 = 0;
- break;
- }
-
- ++s;
-
- if ( *s == MAGIC_RIGHT )
- {
- sub2 = -1;
- break;
- }
-
- if ( !isdigit( *s ) && ( *s != '-' ) )
- {
- sub2 = 0;
- break;
- }
-
- /* First, compute the index of the last element. */
- sub2 = atoi( s );
- while ( isdigit( *++s ) );
-
- if ( *s != MAGIC_RIGHT )
- sub2 = 0;
-
- } while ( 0 );
-
- /* Anything but the end of the string, or the colon introducing
- * a modifier is a syntax error.
- */
- ++s;
- if ( *s && ( *s != MAGIC_COLON ) )
- sub2 = 0;
-
- *bracket = '\0';
- }
-
- /* Get variable value, with special handling for $(<), $(>), $(n).
- */
- if ( !varname[1] )
- {
- if ( varname[0] == '<' )
- value = lol_get( lol, 0 );
- else if ( varname[0] == '>' )
- value = lol_get( lol, 1 );
- else if ( ( varname[0] >= '1' ) && ( varname[0] <= '9' ) )
- value = lol_get( lol, varname[0] - '1' );
- else if( varname[0] == '1' && varname[1] >= '0' &&
- varname[1] <= '9' && !varname[2] )
- value = lol_get( lol, varname[1] - '0' + 10 - 1 );
- }
-
- if ( !value )
- value = var_get( varname );
-
- /* Handle negitive indexes: part two. */
- {
- int length = list_length( value );
-
- if ( sub1 < 0 )
- sub1 = length + sub1;
- else
- sub1 -= 1;
-
- if ( sub2 < 0 )
- sub2 = length + 1 + sub2 - sub1;
- else
- sub2 -= sub1;
- /* The "sub2 < 0" test handles the semantic error of sub2 <
- * sub1.
- */
- if ( sub2 < 0 )
- sub2 = 0;
- }
-
- /* The fast path: $(x) - just copy the variable value. This is only
- * an optimization.
- */
- if ( ( out == out_buf ) && !bracket && !colon && ( in == end ) )
- {
- string_free( variable );
- l = list_copy( l, value );
- continue;
- }
-
- /* Handle start subscript. */
- while ( ( sub1 > 0 ) && value )
- --sub1, value = list_next( value );
-
- /* Empty w/ :E=default?. */
- if ( !value && colon && edits.empty.ptr )
- evalue = value = list_new( L0, newstr( edits.empty.ptr ) );
-
- /* For each variable value. */
- string_new( out1 );
- for ( ; value; value = list_next( value ) )
- {
- LIST * rem;
- size_t postfix_start;
-
- /* Handle end subscript (length actually). */
-
- if ( sub2 >= 0 && --sub2 < 0 )
- break;
-
- string_truncate( buf, prefix_length );
-
- /* Apply : mods, if present */
-
- if ( colon && edits.filemods )
- var_edit_file( value->string, out1, &edits );
- else
- string_append( out1, value->string );
-
- if ( colon && ( edits.upshift || edits.downshift || edits.to_slashes || edits.to_windows ) )
- var_edit_shift( out1, &edits );
-
- /* Handle :J=joinval */
- /* If we have more values for this var, just keep appending them
- * (using the join value) rather than creating separate LIST
- * elements.
- */
- if ( colon && edits.join.ptr &&
- ( list_next( value ) || list_next( vars ) ) )
- {
- string_append( out1, edits.join.ptr );
- continue;
- }
-
- string_append( buf, out1->value );
- string_free( out1 );
- string_new( out1 );
-
- /* If no remainder, append result to output chain. */
- if ( in == end )
- {
- l = list_new( l, newstr( buf->value ) );
- continue;
- }
-
- /* For each remainder, append the complete string to the output
- * chain. Remember the end of the variable expansion so we can
- * just tack on each instance of 'remainder'.
- */
- postfix_start = buf->size;
- for ( rem = remainder; rem; rem = list_next( rem ) )
- {
- string_truncate( buf, postfix_start );
- string_append( buf, rem->string );
- l = list_new( l, newstr( buf->value ) );
- }
- }
- string_free( out1 );
-
- /* Toss used empty. */
- if ( evalue )
- list_free( evalue );
-
- string_free( variable );
- }
-
- /* variables & remainder were gifts from var_expand and must be freed. */
- if ( variables ) list_free( variables );
- if ( remainder ) list_free( remainder );
-
- if ( DEBUG_VAREXP )
- {
- printf( "expanded to " );
- list_print( l );
- printf( "\n" );
- }
-
- string_free( buf );
- return l;
- }
-}
-
-
-/*
- * var_edit_parse() - parse : modifiers into PATHNAME structure
- *
- * The : modifiers in a $(varname:modifier) currently support replacing or
- * omitting elements of a filename, and so they are parsed into a PATHNAME
- * structure (which contains pointers into the original string).
- *
- * Modifiers of the form "X=value" replace the component X with the given value.
- * Modifiers without the "=value" cause everything but the component X to be
- * omitted. X is one of:
- *
- * G <grist>
- * D directory name
- * B base name
- * S .suffix
- * M (member)
- * R root directory - prepended to whole path
- *
- * This routine sets:
- *
- * f->f_xxx.ptr = 0
- * f->f_xxx.len = 0
- * -> leave the original component xxx
- *
- * f->f_xxx.ptr = string
- * f->f_xxx.len = strlen( string )
- * -> replace component xxx with string
- *
- * f->f_xxx.ptr = ""
- * f->f_xxx.len = 0
- * -> omit component xxx
- *
- * var_edit_file() below and path_build() obligingly follow this convention.
- */
-
-static void var_edit_parse( char * mods, VAR_EDITS * edits )
-{
- int havezeroed = 0;
- memset( (char *)edits, 0, sizeof( *edits ) );
-
- while ( *mods )
- {
- char * p;
- PATHPART * fp;
-
- switch ( *mods++ )
- {
- case 'L': edits->downshift = 1; continue;
- case 'U': edits->upshift = 1; continue;
- case 'P': edits->parent = edits->filemods = 1; continue;
- case 'E': fp = &edits->empty; goto strval;
- case 'J': fp = &edits->join; goto strval;
- case 'G': fp = &edits->f.f_grist; goto fileval;
- case 'R': fp = &edits->f.f_root; goto fileval;
- case 'D': fp = &edits->f.f_dir; goto fileval;
- case 'B': fp = &edits->f.f_base; goto fileval;
- case 'S': fp = &edits->f.f_suffix; goto fileval;
- case 'M': fp = &edits->f.f_member; goto fileval;
- case 'T': edits->to_slashes = 1; continue;
- case 'W': edits->to_windows = 1; continue;
- default:
- return; /* Should complain, but so what... */
- }
-
- fileval:
- /* Handle :CHARS, where each char (without a following =) selects a
- * particular file path element. On the first such char, we deselect all
- * others (by setting ptr = "", len = 0) and for each char we select
- * that element (by setting ptr = 0).
- */
- edits->filemods = 1;
-
- if ( *mods != '=' )
- {
- if ( !havezeroed++ )
- {
- int i;
- for ( i = 0; i < 6; ++i )
- {
- edits->f.part[ i ].len = 0;
- edits->f.part[ i ].ptr = "";
- }
- }
-
- fp->ptr = 0;
- continue;
- }
-
- strval:
- /* Handle :X=value, or :X */
- if ( *mods != '=' )
- {
- fp->ptr = "";
- fp->len = 0;
- }
- else if ( ( p = strchr( mods, MAGIC_COLON ) ) )
- {
- *p = 0;
- fp->ptr = ++mods;
- fp->len = p - mods;
- mods = p + 1;
- }
- else
- {
- fp->ptr = ++mods;
- fp->len = strlen( mods );
- mods += fp->len;
- }
- }
-}
-
-
-/*
- * var_edit_file() - copy input target name to output, modifying filename.
- */
-
-static void var_edit_file( char * in, string * out, VAR_EDITS * edits )
-{
- PATHNAME pathname;
-
- /* Parse apart original filename, putting parts into "pathname". */
- path_parse( in, &pathname );
-
- /* Replace any pathname with edits->f */
- if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
- if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
- if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
- if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
- if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
- if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
-
- /* If requested, modify pathname to point to parent. */
- if ( edits->parent )
- path_parent( &pathname );
-
- /* Put filename back together. */
- path_build( &pathname, out, 0 );
-}
-
-
-/*
- * var_edit_shift() - do upshift/downshift mods.
- */
-
-static void var_edit_shift( string * out, VAR_EDITS * edits )
-{
- /* Handle upshifting, downshifting and slash translation now. */
- char * p;
- for ( p = out->value; *p; ++p)
- {
- if ( edits->upshift )
- *p = toupper( *p );
- else if ( edits->downshift )
- *p = tolower( *p );
- if ( edits->to_slashes && ( *p == '\\' ) )
- *p = '/';
-# ifdef OS_CYGWIN
- if ( edits->to_windows )
- {
- char result[ MAX_PATH + 1 ];
- cygwin_conv_to_win32_path( out->value, result );
- assert( strlen( result ) <= MAX_PATH );
- string_free( out );
- string_copy( out, result );
- }
-# endif
- }
- out->size = p - out->value;
-}
-
-
-#ifndef NDEBUG
-void var_expand_unit_test()
-{
- LOL lol[ 1 ];
- LIST * l;
- LIST * l2;
- LIST * expected = list_new( list_new( L0, newstr( "axb" ) ), newstr( "ayb" ) );
- LIST * e2;
- char axyb[] = "a$(xy)b";
- char azb[] = "a$($(z))b";
- char path[] = "$(p:W)";
-
-# ifdef OS_CYGWIN
- char cygpath[ 256 ];
- cygwin_conv_to_posix_path( "c:\\foo\\bar", cygpath );
-# else
- char cygpath[] = "/cygdrive/c/foo/bar";
-# endif
-
- lol_init(lol);
- var_set( "xy", list_new( list_new( L0, newstr( "x" ) ), newstr( "y" ) ), VAR_SET );
- var_set( "z", list_new( L0, newstr( "xy" ) ), VAR_SET );
- var_set( "p", list_new( L0, newstr( cygpath ) ), VAR_SET );
-
- l = var_expand( 0, axyb, axyb + sizeof( axyb ) - 1, lol, 0 );
- for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next( l2 ), e2 = list_next( e2 ) )
- assert( !strcmp( e2->string, l2->string ) );
- assert( l2 == 0 );
- assert( e2 == 0 );
- list_free( l );
-
- l = var_expand( 0, azb, azb + sizeof( azb ) - 1, lol, 0 );
- for ( l2 = l, e2 = expected; l2 && e2; l2 = list_next( l2 ), e2 = list_next( e2 ) )
- assert( !strcmp( e2->string, l2->string ) );
- assert( l2 == 0 );
- assert( e2 == 0 );
- list_free( l );
-
- l = var_expand( 0, path, path + sizeof( path ) - 1, lol, 0 );
- assert( l != 0 );
- assert( list_next( l ) == 0 );
-# ifdef OS_CYGWIN
- /* On some installations of cygwin the drive letter is expanded to other
- * case. This has been reported to be the case if cygwin has been installed
- * to C:\ as opposed to C:\cygwin. Since case of the drive letter will not
- * matter, we allow for both.
- */
- assert( !strcmp( l->string, "c:\\foo\\bar" ) ||
- !strcmp( l->string, "C:\\foo\\bar" ) );
-# else
- assert( !strcmp( l->string, cygpath ) );
-# endif
- list_free( l );
- list_free( expected );
- lol_free( lol );
-}
-#endif
diff --git a/tools/build/v2/engine/expand.h b/tools/build/v2/engine/expand.h
deleted file mode 100644
index cc25d19090..0000000000
--- a/tools/build/v2/engine/expand.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/*
- * expand.h - expand a buffer, given variable values
- */
-
-#include "lists.h"
-
-LIST *var_expand( LIST *l, char *in, char *end, LOL *lol, int cancopyin );
-void var_expand_unit_test();
diff --git a/tools/build/v2/engine/filemac.c b/tools/build/v2/engine/filemac.c
deleted file mode 100644
index e69aa648f3..0000000000
--- a/tools/build/v2/engine/filemac.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * 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)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-# ifdef OS_MAC
-
-#include <Files.h>
-#include <Folders.h>
-
-# include <:sys:stat.h>
-
-/*
- * filemac.c - manipulate file names and scan directories on macintosh
- *
- * 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
- */
-
-
-void CopyC2PStr( char const * cstr, StringPtr pstr )
-{
- int len;
- for ( len = 0; *cstr && ( len < 255 ); pstr[ ++len ] = *cstr++ );
- pstr[ 0 ] = len;
-}
-
-
-/*
- * file_dirscan() - scan a directory for files.
- */
-
-void file_dirscan( char * dir, scanback func, void * closure )
-{
- PATHNAME f;
- string filename[ 1 ];
- unsigned char fullPath[ 512 ];
-
- FSSpec spec;
- WDPBRec vol;
- Str63 volName;
- CInfoPBRec lastInfo;
- int index = 1;
-
- /* First enter directory itself. */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- /* Special case ":" - enter it */
-
- if ( ( f.f_dir.len == 1 ) && ( f.f_dir.ptr[0] == ':' ) )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
-
- /* Now enter contents of directory */
-
- vol.ioNamePtr = volName;
-
- if ( PBHGetVolSync( &vol ) )
- return;
-
- CopyC2PStr( dir, fullPath );
-
- if ( FSMakeFSSpec( vol.ioWDVRefNum, vol.ioWDDirID, fullPath, &spec ) )
- return;
-
- lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
- lastInfo.dirInfo.ioDrDirID = spec.parID;
- lastInfo.dirInfo.ioNamePtr = spec.name;
- lastInfo.dirInfo.ioFDirIndex = 0;
- lastInfo.dirInfo.ioACUser = 0;
-
- if ( PBGetCatInfoSync( &lastInfo ) )
- return;
-
- if ( !( lastInfo.dirInfo.ioFlAttrib & 0x10 ) )
- return;
-
- /* ioDrDirID must be reset each time. */
- spec.parID = lastInfo.dirInfo.ioDrDirID;
-
- string_new( filename );
- for ( ; ; )
- {
- lastInfo.dirInfo.ioVRefNum = spec.vRefNum;
- lastInfo.dirInfo.ioDrDirID = spec.parID;
- lastInfo.dirInfo.ioNamePtr = fullPath;
- lastInfo.dirInfo.ioFDirIndex = index++;
-
- if ( PBGetCatInfoSync( &lastInfo ) )
- return;
-
- f.f_base.ptr = (char *)fullPath + 1;
- f.f_base.len = *fullPath;
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
- (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
- }
- string_free( filename );
-}
-
-
-/*
- * file_time() - get timestamp of file, if not done by file_dirscan().
- */
-
-int file_time( char * filename, time_t * time )
-{
- struct stat statbuf;
-
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
-
- *time = statbuf.st_mtime;
-
- return 0;
-}
-
-
-int file_is_file( char * filename )
-{
- struct stat statbuf;
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
- return S_ISREG( statbuf.st_mode ) ? 1 : 0;
-}
-
-int file_mkdir(char *pathname)
-{
- return mkdir(pathname, 0766);
-}
-
-
-/*
- * file_archscan() - scan an archive for files.
- */
-
-void file_archscan( char * archive, scanback func, void * closure )
-{
-}
-
-
-# endif /* macintosh */
diff --git a/tools/build/v2/engine/filent.c b/tools/build/v2/engine/filent.c
index ab18957677..b448cd03f7 100644
--- a/tools/build/v2/engine/filent.c
+++ b/tools/build/v2/engine/filent.c
@@ -16,7 +16,7 @@
# include "filesys.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# ifdef OS_NT
@@ -57,20 +57,19 @@
* file_dirscan() - scan a directory for files
*/
-void file_dirscan( char * dir, scanback func, void * closure )
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
PROFILE_ENTER( FILE_DIRSCAN );
file_info_t * d = 0;
- dir = short_path_to_long_path( dir );
-
/* First enter directory itself */
d = file_query( dir );
if ( !d || !d->is_dir )
{
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -84,11 +83,15 @@ void file_dirscan( char * dir, scanback func, void * closure )
int ret;
struct _finddata_t finfo[ 1 ];
LIST * files = L0;
- int d_length = strlen( d->name );
+ 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 = d->name;
+ f.f_dir.ptr = object_str( dir );
f.f_dir.len = d_length;
/* Now enter contents of directory */
@@ -103,8 +106,8 @@ void file_dirscan( char * dir, scanback func, void * closure )
* its trailing path separator or otherwise we would not support the
* Windows root folder specified without its drive letter, i.e. '\'.
*/
- char trailingChar = d->name[ d_length - 1 ] ;
- string_copy( filespec, d->name );
+ char trailingChar = object_str( dir )[ d_length - 1 ] ;
+ string_copy( filespec, object_str( dir ) );
if ( ( trailingChar != '\\' ) && ( trailingChar != '/' ) )
string_append( filespec, "\\" );
string_append( filespec, "*" );
@@ -117,6 +120,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
if ( ret = findfirst( filespec->value, finfo, FA_NORMAL | FA_DIREC ) )
{
string_free( filespec );
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -132,7 +136,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename );
- files = list_new( files, newstr(filename->value) );
+ 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;
@@ -147,6 +151,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
if ( ret = ( handle < 0L ) )
{
string_free( filespec );
+ object_free( dir );
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
@@ -154,6 +159,7 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_new( filename );
while ( !ret )
{
+ OBJECT * filename_obj;
file_info_t * ff = 0;
f.f_base.ptr = finfo->name;
@@ -162,8 +168,10 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename, 0 );
- files = list_new( files, newstr( filename->value ) );
- ff = file_info( filename->value );
+ 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;
@@ -176,17 +184,26 @@ void file_dirscan( char * dir, scanback func, void * closure )
# endif
string_free( filename );
string_free( filespec );
+ object_free( dir );
d->files = files;
}
/* Special case \ or d:\ : enter it */
{
- unsigned long len = strlen(d->name);
- if ( len == 1 && d->name[0] == '\\' )
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
- else if ( len == 3 && d->name[1] == ':' ) {
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+ unsigned long len = strlen( object_str( d->name ) );
+ if ( len == 1 && object_str( d->name )[0] == '\\' )
+ {
+ 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] == ':' )
+ {
+ 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
@@ -199,34 +216,38 @@ void file_dirscan( char * dir, scanback func, void * closure )
There will be no trailing slash in $(p), but there will be one
in $(p2). But, that seems rather fragile.
*/
- d->name[2] = 0;
- (*func)( closure, d->name, 1 /* stat()'ed */, d->time );
+ 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 );
}
}
/* Now enter contents of directory */
- if ( d->files )
+ if ( !list_empty( d->files ) )
{
LIST * files = d->files;
- while ( files )
+ LISTITER iter = list_begin( files ), end = list_end( files );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- file_info_t * ff = file_info( files->string );
- (*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
- files = list_next( files );
+ file_info_t * ff = file_info( list_item( iter ) );
+ (*func)( closure, list_item( iter ), 1 /* stat()'ed */, ff->time );
}
}
PROFILE_EXIT( FILE_DIRSCAN );
}
-file_info_t * file_query( char * filename )
+file_info_t * file_query( OBJECT * filename )
{
file_info_t * ff = file_info( filename );
if ( ! ff->time )
{
struct stat statbuf;
- if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
+ if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
return 0;
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
@@ -243,8 +264,8 @@ file_info_t * file_query( char * filename )
int
file_time(
- char *filename,
- time_t *time )
+ OBJECT * filename,
+ time_t * time )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
@@ -252,14 +273,14 @@ file_time(
return 0;
}
-int file_is_file(char* filename)
+int file_is_file( OBJECT * filename )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
return ff->is_file;
}
-int file_mkdir(char *pathname)
+int file_mkdir( const char * pathname )
{
return _mkdir(pathname);
}
@@ -290,9 +311,9 @@ struct ar_hdr {
void
file_archscan(
- char *archive,
- scanback func,
- void *closure )
+ const char * archive,
+ scanback func,
+ void * closure )
{
struct ar_hdr ar_hdr;
char *string_table = 0;
@@ -320,9 +341,10 @@ file_archscan(
{
long lar_date;
long lar_size;
- char *name = 0;
- char *endname;
- char *c;
+ char * name = 0;
+ char * endname;
+ char * c;
+ OBJECT * member;
sscanf( ar_hdr.ar_date, "%ld", &lar_date );
sscanf( ar_hdr.ar_size, "%ld", &lar_size );
@@ -375,7 +397,9 @@ file_archscan(
name = c + 1;
sprintf( buf, "%s(%.*s)", archive, endname - name, name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
offset += SARHDR + lar_size;
lseek( fd, offset, 0 );
diff --git a/tools/build/v2/engine/fileos2.c b/tools/build/v2/engine/fileos2.c
deleted file mode 100644
index af2373ea83..0000000000
--- a/tools/build/v2/engine/fileos2.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * 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)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-/* note that we use "fileunix.c" when compiling with EMX on OS/2 */
-# if defined(OS_OS2) && !defined(__EMX__)
-
-# include <io.h>
-# include <dos.h>
-
-/*
- * fileos2.c - scan directories and archives on NT
- *
- * 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().
- *
- * 07/10/95 (taylor) Findfirst() returns the first file on NT.
- * 05/03/96 (seiwald) split apart into pathnt.c
- * 09/22/00 (seiwald) handle \ and c:\ specially: don't add extra /
- */
-
-/*
- * file_dirscan() - scan a directory for files
- */
-
-void
-file_dirscan(
- char *dir,
- scanback func,
- void *closure )
-{
- PATHNAME f;
- string filespec[1];
- long handle;
- int ret;
- struct _find_t finfo[1];
-
- /* First enter directory itself */
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_dir.ptr = dir;
- f.f_dir.len = strlen(dir);
-
- dir = *dir ? dir : ".";
-
- /* Special case \ or d:\ : enter it */
- string_copy( filespec, dir );
-
- if ( f.f_dir.len == 1 && f.f_dir.ptr[0] == '\\' )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
- else if ( f.f_dir.len == 3 && f.f_dir.ptr[1] == ':' )
- (*func)( closure, dir, 0 /* not stat()'ed */, (time_t)0 );
- else
- string_push_back( filespec, '/' );
-
- string_push_back( filespec, '*' );
-
- /* Now enter contents of directory */
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", filespec->value );
-
- /* Time info in dos find_t is not very useful. It consists */
- /* of a separate date and time, and putting them together is */
- /* not easy. So we leave that to a later stat() call. */
-
- if ( !_dos_findfirst( filespec->value, _A_NORMAL|_A_RDONLY|_A_SUBDIR, finfo ) )
- {
- string filename[1];
- string_new( filename );
- do
- {
- f.f_base.ptr = finfo->name;
- f.f_base.len = strlen( finfo->name );
-
- string_truncate( filename, 0 );
- path_build( &f, filename, 0 );
- (*func)( closure, filename->value, 0 /* not stat()'ed */, (time_t)0 );
- }
- while ( !_dos_findnext( finfo ) );
- string_free( filename );
- }
-}
-
-/*
- * file_time() - get timestamp of file, if not done by file_dirscan()
- */
-
-int
-file_time(
- char *filename,
- time_t *time )
-{
- /* This is called on OS2, not NT. */
- /* NT fills in the time in the dirscan. */
-
- struct stat statbuf;
-
- if ( stat( filename, &statbuf ) < 0 )
- return -1;
-
- *time = statbuf.st_mtime;
-
- return 0;
-}
-
-void
-file_archscan(
- char *archive,
- scanback func,
- void *closure )
-{
-}
-
-# endif /* OS2 && !__EMX__ */
-
diff --git a/tools/build/v2/engine/filesys.c b/tools/build/v2/engine/filesys.c
index eb62ed4060..8d174cfd8b 100644
--- a/tools/build/v2/engine/filesys.c
+++ b/tools/build/v2/engine/filesys.c
@@ -1,7 +1,7 @@
# include "jam.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# include "filesys.h"
# include "lists.h"
@@ -36,25 +36,30 @@ void file_build1( PATHNAME * f, string * file )
static struct hash * filecache_hash = 0;
static file_info_t filecache_finfo;
-file_info_t * file_info(char * filename)
+file_info_t * file_info( OBJECT * filename )
{
file_info_t *finfo = &filecache_finfo;
+ int found;
if ( !filecache_hash )
filecache_hash = hashinit( sizeof( file_info_t ), "file_info" );
- finfo->name = filename;
- finfo->is_file = 0;
- finfo->is_dir = 0;
- finfo->size = 0;
- finfo->time = 0;
- finfo->files = 0;
- if ( hashenter( filecache_hash, (HASHDATA**)&finfo ) )
+ filename = path_as_key( filename );
+
+ finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found );
+ if ( !found )
{
/* printf( "file_info: %s\n", filename ); */
- finfo->name = newstr( finfo->name );
+ finfo->name = object_copy( filename );
+ finfo->is_file = 0;
+ finfo->is_dir = 0;
+ finfo->size = 0;
+ finfo->time = 0;
+ finfo->files = L0;
}
+ object_free( filename );
+
return finfo;
}
@@ -62,22 +67,33 @@ static LIST * files_to_remove = L0;
static void remove_files_atexit(void)
{
- /* we do pop front in case this exit function is called
- more than once */
- while ( files_to_remove )
+ LISTITER iter = list_begin( files_to_remove ), end = list_end( files_to_remove );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- remove( files_to_remove->string );
- files_to_remove = list_pop_front( files_to_remove );
+ remove( object_str( list_item( iter ) ) );
}
+ list_free( files_to_remove );
+ files_to_remove = L0;
+}
+
+static void free_file_info ( void * xfile, void * data )
+{
+ file_info_t * file = (file_info_t *)xfile;
+ object_free( file->name );
+ list_free( file->files );
}
void file_done()
{
remove_files_atexit();
- hashdone( filecache_hash );
+ if ( filecache_hash )
+ {
+ hashenumerate( filecache_hash, free_file_info, (void *)0 );
+ hashdone( filecache_hash );
+ }
}
-void file_remove_atexit( const char * path )
+void file_remove_atexit( OBJECT * path )
{
- files_to_remove = list_new( files_to_remove, newstr((char*)path) );
+ files_to_remove = list_push_back( files_to_remove, object_copy( path ) );
}
diff --git a/tools/build/v2/engine/filesys.h b/tools/build/v2/engine/filesys.h
index efc081d120..d32805126e 100644
--- a/tools/build/v2/engine/filesys.h
+++ b/tools/build/v2/engine/filesys.h
@@ -20,22 +20,23 @@
# include "pathsys.h"
#include "hash.h"
#include "lists.h"
+#include "object.h"
-typedef void (*scanback)( void *closure, char *file, int found, time_t t );
+typedef void (*scanback)( void *closure, OBJECT * file, int found, time_t t );
-void file_dirscan( char *dir, scanback func, void *closure );
-void file_archscan( char *arch, scanback func, void *closure );
+void file_dirscan( OBJECT * dir, scanback func, void * closure );
+void file_archscan( const char * arch, scanback func, void * closure );
-int file_time( char *filename, time_t *time );
+int file_time( OBJECT * filename, time_t * time );
void file_build1(PATHNAME *f, string* file) ;
-int file_is_file(char* filename);
-int file_mkdir(char *pathname);
+int file_is_file( OBJECT * filename );
+int file_mkdir( const char * pathname );
typedef struct file_info_t file_info_t ;
struct file_info_t
{
- char * name;
+ OBJECT * name;
short is_file;
short is_dir;
unsigned long size;
@@ -47,14 +48,14 @@ struct file_info_t
/* 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( char * filename );
+file_info_t * file_info( OBJECT * filename );
/* Returns information about a file, queries the OS if needed. */
-file_info_t * file_query( char * filename );
+file_info_t * file_query( OBJECT * filename );
void file_done();
/* Marks a path/file to be removed when jam exits. */
-void file_remove_atexit( const char * path );
+void file_remove_atexit( OBJECT * path );
#endif
diff --git a/tools/build/v2/engine/fileunix.c b/tools/build/v2/engine/fileunix.c
index 680c3f5394..d8b458c9ba 100644
--- a/tools/build/v2/engine/fileunix.c
+++ b/tools/build/v2/engine/fileunix.c
@@ -15,7 +15,7 @@
# include "filesys.h"
# include "strings.h"
# include "pathsys.h"
-# include "newstr.h"
+# include "object.h"
# include <stdio.h>
# include <sys/stat.h>
@@ -125,7 +125,7 @@ struct ar_hdr /* archive file member header - printable ascii */
* file_dirscan() - scan a directory for files.
*/
-void file_dirscan( char * dir, scanback func, void * closure )
+void file_dirscan( OBJECT * dir, scanback func, void * closure )
{
PROFILE_ENTER( FILE_DIRSCAN );
@@ -139,37 +139,39 @@ void file_dirscan( char * dir, scanback func, void * closure )
return;
}
- if ( ! d->files )
+ 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 = dir;
- f.f_dir.len = strlen(dir);
+ f.f_dir.ptr = dirstr;
+ f.f_dir.len = strlen( dirstr );
- dir = *dir ? dir : ".";
+ dirstr = *dirstr ? dirstr : ".";
/* Now enter contents of directory. */
- if ( !( dd = opendir( dir ) ) )
+ if ( !( dd = opendir( dirstr ) ) )
{
PROFILE_EXIT( FILE_DIRSCAN );
return;
}
if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
+ printf( "scan directory %s\n", dirstr );
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;
@@ -181,8 +183,9 @@ void file_dirscan( char * dir, scanback func, void * closure )
string_truncate( filename, 0 );
path_build( &f, filename, 0 );
- files = list_new( files, newstr(filename->value) );
- file_query( filename->value );
+ filename_obj = object_new( filename->value );
+ files = list_push_back( files, filename_obj );
+ file_query( filename_obj );
}
string_free( filename );
@@ -193,18 +196,18 @@ void file_dirscan( char * dir, scanback func, void * closure )
/* Special case / : enter it */
{
- unsigned long len = strlen(d->name);
- if ( ( len == 1 ) && ( d->name[0] == '/' ) )
+ if ( strcmp( object_str( d->name ), "/" ) == 0 )
(*func)( closure, d->name, 1 /* stat()'ed */, d->time );
}
/* Now enter contents of directory */
- if ( d->files )
+ if ( !list_empty( d->files ) )
{
LIST * files = d->files;
- while ( files )
+ LISTITER iter = list_begin( files ), end = list_end( files );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- file_info_t * ff = file_info( files->string );
+ file_info_t * ff = file_info( list_item( iter ) );
(*func)( closure, ff->name, 1 /* stat()'ed */, ff->time );
files = list_next( files );
}
@@ -214,14 +217,14 @@ void file_dirscan( char * dir, scanback func, void * closure )
}
-file_info_t * file_query( char * filename )
+file_info_t * file_query( OBJECT * filename )
{
file_info_t * ff = file_info( filename );
if ( ! ff->time )
{
struct stat statbuf;
- if ( stat( *filename ? filename : ".", &statbuf ) < 0 )
+ if ( stat( *object_str( filename ) ? object_str( filename ) : ".", &statbuf ) < 0 )
return 0;
ff->is_file = statbuf.st_mode & S_IFREG ? 1 : 0;
@@ -238,8 +241,8 @@ file_info_t * file_query( char * filename )
int
file_time(
- char *filename,
- time_t *time )
+ OBJECT * filename,
+ time_t * time )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
@@ -247,16 +250,16 @@ file_time(
return 0;
}
-int file_is_file(char* filename)
+int file_is_file( OBJECT * filename )
{
file_info_t * ff = file_query( filename );
if ( !ff ) return -1;
return ff->is_file;
}
-int file_mkdir(char* pathname)
+int file_mkdir( const char * pathname )
{
- return mkdir(pathname, 0766);
+ return mkdir( pathname, 0766 );
}
/*
@@ -270,9 +273,9 @@ int file_mkdir(char* pathname)
void
file_archscan(
- char *archive,
+ const char * archive,
scanback func,
- void *closure )
+ void * closure )
{
# ifndef NO_AR
struct ar_hdr ar_hdr;
@@ -312,6 +315,7 @@ file_archscan(
char * c;
char * src;
char * dest;
+ OBJECT * member;
strncpy( lar_name, ar_hdr.ar_name, sizeof(ar_hdr.ar_name) );
@@ -356,14 +360,16 @@ file_archscan(
sprintf( buf, "%s(%s)", archive, lar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
offset += SARHDR + ( ( lar_size + 1 ) & ~1 );
lseek( fd, offset, 0 );
}
- if (string_table)
- BJAM_FREE(string_table);
+ if ( string_table )
+ BJAM_FREE( string_table );
close( fd );
@@ -396,10 +402,11 @@ static void file_archscan_small(
while ( ( offset > 0 )
&& ( lseek( fd, offset, 0 ) >= 0 )
- && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= sizeof( ar_hdr.hdr ) ) )
+ && ( read( fd, &ar_hdr, sizeof( ar_hdr ) ) >= (int)sizeof( ar_hdr.hdr ) ) )
{
long lar_date;
int lar_namlen;
+ OBJECT * member;
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
sscanf( ar_hdr.hdr.ar_date , "%ld", &lar_date );
@@ -412,7 +419,9 @@ static void file_archscan_small(
sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
}
}
@@ -446,6 +455,7 @@ static void file_archscan_big(
{
long lar_date;
int lar_namlen;
+ OBJECT * member;
sscanf( ar_hdr.hdr.ar_namlen, "%d" , &lar_namlen );
sscanf( ar_hdr.hdr.ar_date , "%ld" , &lar_date );
@@ -458,19 +468,21 @@ static void file_archscan_big(
sprintf( buf, "%s(%s)", archive, ar_hdr.hdr._ar_name.ar_name );
- (*func)( closure, buf, 1 /* time valid */, (time_t)lar_date );
+ member = object_new( buf );
+ (*func)( closure, member, 1 /* time valid */, (time_t)lar_date );
+ object_free( member );
}
}
#endif /* AR_HSZ_BIG */
-void file_archscan(char *archive, scanback func, void *closure)
+void file_archscan( const char * archive, scanback func, void *closure)
{
int fd;
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
@@ -480,16 +492,16 @@ void file_archscan(char *archive, scanback func, void *closure)
return;
}
- if (strncmp(AIAMAG, fl_magic, SAIAMAG) == 0)
+ if ( strncmp( AIAMAG, fl_magic, SAIAMAG ) == 0 )
{
/* read small variant */
- file_archscan_small(fd, archive, func, closure);
+ 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 ) == 0 )
{
/* read big variant */
- file_archscan_big(fd, archive, func, closure);
+ file_archscan_big( fd, archive, func, closure );
}
#endif
diff --git a/tools/build/v2/engine/filevms.c b/tools/build/v2/engine/filevms.c
deleted file mode 100644
index d2ab2047f0..0000000000
--- a/tools/build/v2/engine/filevms.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * 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)
- */
-
-# include "jam.h"
-# include "filesys.h"
-# include "pathsys.h"
-
-# ifdef OS_VMS
-
-/*
- * filevms.c - scan directories and libaries on VMS
- *
- * 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().
- *
- * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
- * 05/03/96 (seiwald) - split into pathvms.c
- */
-
-# include <rms.h>
-# include <iodef.h>
-# include <ssdef.h>
-# include <string.h>
-# include <stdlib.h>
-# include <stdio.h>
-# include <descrip.h>
-
-#include <lbrdef.h>
-#include <credef.h>
-#include <mhddef.h>
-#include <lhidef.h>
-#include <lib$routines.h>
-#include <starlet.h>
-
-/* Supply missing prototypes for lbr$-routines*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-int lbr$set_module(
- void **,
- unsigned long *,
- struct dsc$descriptor_s *,
- unsigned short *,
- void * );
-
-int lbr$open( void **,
- struct dsc$descriptor_s *,
- void *,
- void *,
- void *,
- void *,
- void * );
-
-int lbr$ini_control(
- void **,
- unsigned long *,
- unsigned long *,
- void * );
-
-int lbr$get_index(
- void **,
- unsigned long *,
- int (*func)( struct dsc$descriptor_s *, unsigned long *),
- void * );
-
-int lbr$close(
- void ** );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void
-file_cvttime(
- unsigned int *curtime,
- time_t *unixtime )
-{
- static const size_t divisor = 10000000;
- static unsigned int bastim[2] = { 0x4BEB4000, 0x007C9567 }; /* 1/1/1970 */
- int delta[2], remainder;
-
- lib$subx( curtime, bastim, delta );
- lib$ediv( &divisor, delta, unixtime, &remainder );
-}
-
-# define DEFAULT_FILE_SPECIFICATION "[]*.*;0"
-
-# define min( a,b ) ((a)<(b)?(a):(b))
-
-void
-file_dirscan(
- char *dir,
- scanback func,
- void *closure )
-{
-
- struct FAB xfab;
- struct NAM xnam;
- struct XABDAT xab;
- char esa[256];
- char filename[256];
- string filename2[1];
- char dirname[256];
- register int status;
- PATHNAME f;
-
- memset( (char *)&f, '\0', sizeof( f ) );
-
- f.f_root.ptr = dir;
- f.f_root.len = strlen( dir );
-
- /* get the input file specification
- */
- xnam = cc$rms_nam;
- xnam.nam$l_esa = esa;
- xnam.nam$b_ess = sizeof( esa ) - 1;
- xnam.nam$l_rsa = filename;
- xnam.nam$b_rss = min( sizeof( filename ) - 1, NAM$C_MAXRSS );
-
- xab = cc$rms_xabdat; /* initialize extended attributes */
- xab.xab$b_cod = XAB$C_DAT; /* ask for date */
- xab.xab$l_nxt = NULL; /* terminate XAB chain */
-
- xfab = cc$rms_fab;
- xfab.fab$l_dna = DEFAULT_FILE_SPECIFICATION;
- xfab.fab$b_dns = sizeof( DEFAULT_FILE_SPECIFICATION ) - 1;
- xfab.fab$l_fop = FAB$M_NAM;
- xfab.fab$l_fna = dir; /* address of file name */
- xfab.fab$b_fns = strlen( dir ); /* length of file name */
- xfab.fab$l_nam = &xnam; /* address of NAB block */
- xfab.fab$l_xab = (char *)&xab; /* address of XAB block */
-
-
- status = sys$parse( &xfab );
-
- if ( DEBUG_BINDSCAN )
- printf( "scan directory %s\n", dir );
-
- if ( !( status & 1 ) )
- return;
-
-
-
- /* Add bogus directory for [000000] */
-
- if ( !strcmp( dir, "[000000]" ) )
- {
- (*func)( closure, "[000000]", 1 /* time valid */, 1 /* old but true */ );
- }
-
- /* Add bogus directory for [] */
-
- if ( !strcmp( dir, "[]" ) )
- {
- (*func)( closure, "[]", 1 /* time valid */, 1 /* old but true */ );
- (*func)( closure, "[-]", 1 /* time valid */, 1 /* old but true */ );
- }
-
- string_new( filename2 );
- while ( (status = sys$search( &xfab )) & 1 )
- {
- char *s;
- time_t time;
-
- /* "I think that might work" - eml */
-
- sys$open( &xfab );
- sys$close( &xfab );
-
- file_cvttime( (unsigned int *)&xab.xab$q_rdt, &time );
-
- filename[xnam.nam$b_rsl] = '\0';
-
- /* What we do with the name depends on the suffix: */
- /* .dir is a directory */
- /* .xxx is a file with a suffix */
- /* . is no suffix at all */
-
- if ( xnam.nam$b_type == 4 && !strncmp( xnam.nam$l_type, ".DIR", 4 ) )
- {
- /* directory */
- sprintf( dirname, "[.%.*s]", xnam.nam$b_name, xnam.nam$l_name );
- f.f_dir.ptr = dirname;
- f.f_dir.len = strlen( dirname );
- f.f_base.ptr = 0;
- f.f_base.len = 0;
- f.f_suffix.ptr = 0;
- f.f_suffix.len = 0;
- }
- else
- {
- /* normal file with a suffix */
- f.f_dir.ptr = 0;
- f.f_dir.len = 0;
- f.f_base.ptr = xnam.nam$l_name;
- f.f_base.len = xnam.nam$b_name;
- f.f_suffix.ptr = xnam.nam$l_type;
- f.f_suffix.len = xnam.nam$b_type;
- }
-
- string_truncate( filename2, 0 );
- path_build( &f, filename2, 0 );
-
- /*
- if ( DEBUG_SEARCH )
- printf("root '%s' base %.*s suf %.*s = %s\n",
- dir,
- xnam.nam$b_name, xnam.nam$l_name,
- xnam.nam$b_type, xnam.nam$l_type,
- filename2 );
- */
-
- (*func)( closure, filename2->value, 1 /* time valid */, time );
- }
- string_free( filename2 );
-}
-
-int
-file_time(
- char *filename,
- time_t *time )
-{
- /* This should never be called, as all files are */
- /* timestampped in file_dirscan() and file_archscan() */
- return -1;
-}
-
-static char *VMS_archive = 0;
-static scanback VMS_func;
-static void *VMS_closure;
-static void *context;
-
-static int
-file_archmember(
- struct dsc$descriptor_s *module,
- unsigned long *rfa )
-{
- static struct dsc$descriptor_s bufdsc =
- {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
-
- struct mhddef *mhd;
- char filename[128];
- char buf[ MAXJPATH ];
-
- int status;
- time_t library_date;
-
- register int i;
- register char *p;
-
- bufdsc.dsc$a_pointer = filename;
- bufdsc.dsc$w_length = sizeof( filename );
- status = lbr$set_module( &context, rfa, &bufdsc,
- &bufdsc.dsc$w_length, NULL );
-
- if ( !(status & 1) )
- return ( 1 );
-
- mhd = (struct mhddef *)filename;
-
- file_cvttime( &mhd->mhd$l_datim, &library_date );
-
- for ( i = 0, p = module->dsc$a_pointer; i < module->dsc$w_length; ++i, ++p )
- filename[ i ] = *p;
-
- filename[ i ] = '\0';
-
- sprintf( buf, "%s(%s.obj)", VMS_archive, filename );
-
- (*VMS_func)( VMS_closure, buf, 1 /* time valid */, (time_t)library_date );
-
- return ( 1 );
-}
-
-
-void file_archscan( char * archive, scanback func, void * closure )
-{
- static struct dsc$descriptor_s library =
- {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
-
- unsigned long lfunc = LBR$C_READ;
- unsigned long typ = LBR$C_TYP_UNK;
- unsigned long index = 1;
-
- register int status;
-
- VMS_archive = archive;
- VMS_func = func;
- VMS_closure = closure;
-
- status = lbr$ini_control( &context, &lfunc, &typ, NULL );
- if ( !( status & 1 ) )
- return;
-
- library.dsc$a_pointer = archive;
- library.dsc$w_length = strlen( archive );
-
- status = lbr$open( &context, &library, NULL, NULL, NULL, NULL, NULL );
- if ( !( status & 1 ) )
- return;
-
- (void) lbr$get_index( &context, &index, file_archmember, NULL );
-
- (void) lbr$close( &context );
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/frames.c b/tools/build/v2/engine/frames.c
index 84889f09e7..29f7f03cde 100644
--- a/tools/build/v2/engine/frames.c
+++ b/tools/build/v2/engine/frames.c
@@ -13,7 +13,8 @@ void frame_init( FRAME* frame )
lol_init(frame->args);
frame->module = root_module();
frame->rulename = "module scope";
- frame->procedure = 0;
+ frame->file = 0;
+ frame->line = -1;
}
void frame_free( FRAME* frame )
diff --git a/tools/build/v2/engine/frames.h b/tools/build/v2/engine/frames.h
index 693d77fa0a..1e2040d14f 100644
--- a/tools/build/v2/engine/frames.h
+++ b/tools/build/v2/engine/frames.h
@@ -7,6 +7,7 @@
#define FRAMES_DWA20011021_H
#include "lists.h"
+#include "object.h"
#include "modules.h"
typedef struct _PARSE PARSE;
@@ -14,13 +15,14 @@ typedef struct frame FRAME;
struct frame
{
- FRAME * prev;
+ FRAME * prev;
/* The nearest enclosing frame for which module->user_module is true. */
- FRAME * prev_user;
- LOL args[ 1 ];
- module_t * module;
- PARSE * procedure;
- char * rulename;
+ FRAME * prev_user;
+ LOL args[ 1 ];
+ module_t * module;
+ OBJECT * file;
+ int line;
+ const char * rulename;
};
diff --git a/tools/build/v2/engine/function.c b/tools/build/v2/engine/function.c
new file mode 100644
index 0000000000..1688eba4e8
--- /dev/null
+++ b/tools/build/v2/engine/function.c
@@ -0,0 +1,4553 @@
+/*
+ * 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)
+ */
+
+#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 "filesys.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+# ifdef OS_CYGWIN
+# include <sys/cygwin.h>
+# 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
+
+typedef struct instruction
+{
+ unsigned int op_code;
+ int arg;
+} instruction;
+
+typedef struct _subfunction
+{
+ OBJECT * name;
+ FUNCTION * code;
+ int local;
+} SUBFUNCTION;
+
+typedef struct _subaction
+{
+ OBJECT * name;
+ FUNCTION * command;
+ int flags;
+} SUBACTION;
+
+#define FUNCTION_BUILTIN 0
+#define FUNCTION_JAM 1
+
+struct argument {
+ int flags;
+#define ARG_ONE 0
+#define ARG_OPTIONAL 1
+#define ARG_PLUS 2
+#define ARG_STAR 3
+#define ARG_VARIADIC 4
+ OBJECT * type_name;
+ OBJECT * arg_name;
+ int index;
+};
+
+struct arg_list {
+ int size;
+ struct argument * args;
+};
+
+struct _function
+{
+ int type;
+ int reference_count;
+ OBJECT * rulename;
+ struct arg_list * formal_arguments;
+ int num_formal_arguments;
+};
+
+typedef struct _builtin_function
+{
+ FUNCTION base;
+ LIST * ( * func )( FRAME *, int flags );
+ int flags;
+} BUILTIN_FUNCTION;
+
+typedef struct _jam_function
+{
+ FUNCTION base;
+ int code_size;
+ instruction * code;
+ int num_constants;
+ OBJECT * * constants;
+ int num_subfunctions;
+ SUBFUNCTION * functions;
+ int num_subactions;
+ SUBACTION * actions;
+ FUNCTION * generic;
+ OBJECT * file;
+ int line;
+} JAM_FUNCTION;
+
+
+#ifdef HAVE_PYTHON
+
+#define FUNCTION_PYTHON 2
+
+typedef struct _python_function
+{
+ FUNCTION base;
+ PyObject * python_function;
+} PYTHON_FUNCTION;
+
+static LIST * call_python_function( PYTHON_FUNCTION * function, FRAME * frame );
+
+#endif
+
+
+struct _stack
+{
+ void * data;
+};
+
+static void * stack;
+
+STACK * stack_global()
+{
+ static STACK result;
+ if ( !stack )
+ {
+ int size = 1 << 21;
+ stack = BJAM_MALLOC( size );
+ result.data = (char *)stack + size;
+ }
+ return &result;
+}
+
+static void check_alignment( STACK * s )
+{
+ assert( (unsigned long)s->data % sizeof( LIST * ) == 0 );
+}
+
+void * stack_allocate( STACK * s, int size )
+{
+ check_alignment( s );
+ s->data = (char *)s->data - size;
+ check_alignment( s );
+ return s->data;
+}
+
+void stack_deallocate( STACK * s, int size )
+{
+ check_alignment( s );
+ s->data = (char *)s->data + size;
+ check_alignment( s );
+}
+
+void stack_push( STACK * s, LIST * l )
+{
+ *(LIST * *)stack_allocate( s, sizeof( LIST * ) ) = l;
+}
+
+LIST * stack_pop( STACK * s )
+{
+ LIST * result = *(LIST * *)s->data;
+ stack_deallocate( s, sizeof( LIST * ) );
+ return result;
+}
+
+LIST * stack_top(STACK * s)
+{
+ check_alignment( s );
+ return *(LIST * *)s->data;
+}
+
+LIST * stack_at( STACK * s, int n )
+{
+ check_alignment( s );
+ return *((LIST * *)s->data + n);
+}
+
+void stack_set( STACK * s, int n, LIST * value )
+{
+ check_alignment( s );
+ *((LIST * *)s->data + n) = value;
+}
+
+void * stack_get( STACK * s )
+{
+ check_alignment( s );
+ return (LIST * *)s->data;
+}
+
+LIST * frame_get_local( FRAME * frame, int idx )
+{
+ /* The only local variables are the arguments */
+ return list_copy( lol_get( frame->args, idx ) );
+}
+
+static OBJECT * function_get_constant( JAM_FUNCTION * function, int idx )
+{
+ return function->constants[ idx ];
+}
+
+static LIST * function_get_variable( JAM_FUNCTION * function, FRAME * frame, int 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 )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_SET );
+}
+
+static LIST * function_swap_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ return var_swap( frame->module, function->constants[idx], 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 );
+}
+
+static void function_default_variable( JAM_FUNCTION * function, FRAME * frame, int idx, LIST * value )
+{
+ var_set( frame->module, function->constants[idx], value, VAR_DEFAULT );
+}
+
+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 )
+{
+ SUBACTION * sub = function->actions + idx;
+ LIST * bindlist = stack_pop( s );
+
+ 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.
+ */
+
+static int get_argument_index( const char * s )
+{
+ if( s[ 0 ] != '\0')
+ {
+ if( s[ 1 ] == '\0' )
+ {
+ switch ( s[ 0 ] )
+ {
+ case '<': return 0;
+ case '>': return 1;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 0 ] - '1';
+ }
+ }
+ else if ( s[ 0 ] == '1' && s[ 2 ] == '\0' )
+ {
+ switch( s[ 1 ] )
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return s[ 1 ] - '0' + 10 - 1;
+ }
+ }
+ }
+ return -1;
+}
+
+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 ) );
+ }
+}
+
+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 )
+{
+ return var_swap( frame->module, name, 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 )
+{
+ 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 )
+{
+ FRAME inner[ 1 ];
+ int i;
+ LIST * first = stack_pop( s );
+ LIST * result = L0;
+ OBJECT * rulename;
+ LIST * trailing;
+
+ 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(), below. */
+
+ 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 * * l = &inner->args->list[0];
+ *l = list_append( trailing, *l );
+ }
+ }
+
+ result = evaluate_rule( rulename, inner );
+ frame_free( inner );
+ object_free( rulename );
+ return result;
+}
+
+/* Variable expansion */
+
+typedef struct
+{
+ int sub1;
+ int sub2;
+} subscript_t;
+
+typedef struct
+{
+ PATHNAME f; /* :GDBSMR -- pieces */
+ char parent; /* :P -- go to parent directory */
+ char filemods; /* one of the above applied */
+ char downshift; /* :L -- downshift result */
+ char upshift; /* :U -- upshift result */
+ char to_slashes; /* :T -- convert "\" to "/" */
+ char to_windows; /* :W -- convert cygwin to native paths */
+ PATHPART empty; /* :E -- default for empties */
+ 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 );
+
+
+/*
+ * var_edit_parse() - parse : modifiers into PATHNAME structure
+ *
+ * The : modifiers in a $(varname:modifier) currently support replacing or
+ * omitting elements of a filename, and so they are parsed into a PATHNAME
+ * structure (which contains pointers into the original string).
+ *
+ * Modifiers of the form "X=value" replace the component X with the given value.
+ * Modifiers without the "=value" cause everything but the component X to be
+ * omitted. X is one of:
+ *
+ * G <grist>
+ * D directory name
+ * B base name
+ * S .suffix
+ * M (member)
+ * R root directory - prepended to whole path
+ *
+ * This routine sets:
+ *
+ * f->f_xxx.ptr = 0
+ * f->f_xxx.len = 0
+ * -> leave the original component xxx
+ *
+ * f->f_xxx.ptr = string
+ * f->f_xxx.len = strlen( string )
+ * -> replace component xxx with string
+ *
+ * f->f_xxx.ptr = ""
+ * f->f_xxx.len = 0
+ * -> omit component xxx
+ *
+ * var_edit_file() below and path_build() obligingly follow this convention.
+ */
+
+static int var_edit_parse( const char * mods, VAR_EDITS * edits, int havezeroed )
+{
+ while ( *mods )
+ {
+ PATHPART * fp;
+
+ switch ( *mods++ )
+ {
+ case 'L': edits->downshift = 1; continue;
+ case 'U': edits->upshift = 1; continue;
+ case 'P': edits->parent = edits->filemods = 1; continue;
+ case 'E': fp = &edits->empty; goto strval;
+ case 'J': fp = &edits->join; goto strval;
+ case 'G': fp = &edits->f.f_grist; goto fileval;
+ case 'R': fp = &edits->f.f_root; goto fileval;
+ case 'D': fp = &edits->f.f_dir; goto fileval;
+ case 'B': fp = &edits->f.f_base; goto fileval;
+ case 'S': fp = &edits->f.f_suffix; goto fileval;
+ case 'M': fp = &edits->f.f_member; goto fileval;
+ case 'T': edits->to_slashes = 1; continue;
+ case 'W': edits->to_windows = 1; continue;
+ default:
+ continue; /* Should complain, but so what... */
+ }
+
+ fileval:
+ /* Handle :CHARS, where each char (without a following =) selects a
+ * particular file path element. On the first such char, we deselect all
+ * others (by setting ptr = "", len = 0) and for each char we select
+ * that element (by setting ptr = 0).
+ */
+ edits->filemods = 1;
+
+ if ( *mods != '=' )
+ {
+ if ( !havezeroed++ )
+ {
+ int i;
+ for ( i = 0; i < 6; ++i )
+ {
+ edits->f.part[ i ].len = 0;
+ edits->f.part[ i ].ptr = "";
+ }
+ }
+
+ fp->ptr = 0;
+ continue;
+ }
+
+ strval:
+ /* Handle :X=value, or :X */
+ if ( *mods != '=' )
+ {
+ fp->ptr = "";
+ fp->len = 0;
+ }
+ else
+ {
+ fp->ptr = ++mods;
+ fp->len = strlen( mods );
+ mods += fp->len;
+ }
+ }
+
+ 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 )
+{
+ if ( edits->filemods )
+ {
+ PATHNAME pathname;
+
+ /* Parse apart original filename, putting parts into "pathname". */
+ path_parse( in, &pathname );
+
+ /* Replace any pathname with edits->f */
+ if ( edits->f.f_grist .ptr ) pathname.f_grist = edits->f.f_grist;
+ if ( edits->f.f_root .ptr ) pathname.f_root = edits->f.f_root;
+ if ( edits->f.f_dir .ptr ) pathname.f_dir = edits->f.f_dir;
+ if ( edits->f.f_base .ptr ) pathname.f_base = edits->f.f_base;
+ if ( edits->f.f_suffix.ptr ) pathname.f_suffix = edits->f.f_suffix;
+ if ( edits->f.f_member.ptr ) pathname.f_member = edits->f.f_member;
+
+ /* If requested, modify pathname to point to parent. */
+ if ( edits->parent )
+ path_parent( &pathname );
+
+ /* Put filename back together. */
+ path_build( &pathname, out, 0 );
+ }
+ else
+ {
+ string_append( out, in );
+ }
+}
+
+/*
+ * var_edit_shift() - do upshift/downshift mods.
+ */
+
+static void var_edit_shift( string * out, size_t pos, VAR_EDITS * edits )
+{
+ if ( edits->upshift || edits->downshift || edits->to_windows || edits->to_slashes )
+ {
+ /* Handle upshifting, downshifting and slash translation now. */
+ char * p;
+# ifdef OS_CYGWIN
+ if ( edits->to_windows )
+ {
+ /* 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)
+ {
+ if ( edits->upshift )
+ *p = toupper( *p );
+ else if ( edits->downshift )
+ *p = tolower( *p );
+ if ( edits->to_slashes && ( *p == '\\' ) )
+ *p = '/';
+ }
+ }
+}
+
+/*
+ * 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 )
+{
+ int i;
+ int total = 1;
+ LIST * * args = stack_get( s );
+ 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] );
+ }
+ 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 );
+ }
+ ++out;
+ while ( --i >= 0 )
+ {
+ if ( list_next( iter[i] ) != list_end( args[i] ) )
+ {
+ iter[i] = list_next( iter[i] );
+ goto loop;
+ }
+ else
+ {
+ iter[i] = list_begin( args[i] );
+ }
+ }
+ }
+ stack_deallocate( s, n * sizeof( LIST * ) );
+ }
+ return total;
+}
+
+static LIST * apply_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * result = L0;
+ VAR_EDITS * 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 ) );
+ string_free( buf );
+ return result;
+}
+
+/*
+ * 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 result;
+ result.sub1 = 0;
+ result.sub2 = 0;
+ do /* so we can use "break" */
+ {
+ /* Allow negative subscripts. */
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+ result.sub1 = atoi( s );
+
+ /* Skip over the first symbol, which is either a digit or dash. */
+ ++s;
+ while ( isdigit( *s ) ) ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = result.sub1;
+ break;
+ }
+
+ if ( *s != '-' )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ ++s;
+
+ if ( *s == '\0' )
+ {
+ result.sub2 = -1;
+ break;
+ }
+
+ if ( !isdigit( *s ) && ( *s != '-' ) )
+ {
+ result.sub2 = 0;
+ break;
+ }
+
+ /* First, compute the index of the last element. */
+ result.sub2 = atoi( s );
+ while ( isdigit( *++s ) );
+
+ if ( *s != '\0' )
+ result.sub2 = 0;
+
+ } while ( 0 );
+ return result;
+}
+
+static LIST * apply_subscript( STACK * s )
+{
+ LIST * value = stack_top( s );
+ 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_new( buf );
+ 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 ) ) );
+ 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.
+ */
+
+static void get_iters( subscript_t subscript, LISTITER * first, LISTITER * last, int length )
+{
+ int start;
+ int size;
+ LISTITER iter;
+ LISTITER end;
+ {
+
+ if ( subscript.sub1 < 0 )
+ start = length + subscript.sub1;
+ 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;
+
+ /*
+ * 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.
+ */
+ if ( size < 0 )
+ size = 0;
+
+ if ( start + size > length )
+ size = length - start;
+ }
+
+ iter = *first;
+ while ( start-- > 0 )
+ iter = list_next( iter );
+
+ end = iter;
+ while ( size-- > 0 )
+ end = list_next( end );
+
+ *first = iter;
+ *last = end;
+}
+
+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 )
+ {
+ /** FIXME: is empty.ptr always null-terminated? */
+ 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 );
+ }
+ }
+ return result;
+}
+
+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 )
+ {
+ 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 ) )
+ {
+ size_t size;
+ string_append( buf, edits[i].join.ptr );
+ size = buf->size;
+ 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 ) );
+ string_truncate( buf, 0 );
+ }
+ else
+ {
+ for ( iter = begin; iter != end; iter = list_next( iter ) )
+ {
+ var_edit_file( object_str( list_item( iter ) ), buf, edits + i );
+ var_edit_shift( buf, 0, edits + i );
+ result = list_push_back( result, object_new( buf->value ) );
+ string_truncate( buf, 0 );
+ }
+ }
+ }
+ return result;
+}
+
+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 );
+ }
+}
+
+static LIST * apply_subscript_and_modifiers( STACK * s, int n )
+{
+ LIST * value = stack_top( s );
+ LIST * 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 );
+ string_new( buf );
+ 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 ) ) );
+ get_iters( sub, &iter, &end, length );
+ result = apply_modifiers_impl( result, buf, edits, n, iter, end );
+ }
+ string_free( buf );
+ return result;
+}
+
+typedef struct expansion_item
+{
+ LISTITER elem;
+ LIST * saved;
+ int size;
+} expansion_item;
+
+static LIST * expand( expansion_item * elem, int length )
+{
+ LIST * result = L0;
+ 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 ) )
+ {
+ int len = strlen( object_str( list_item( iter ) ) );
+ if ( len > max ) max = len;
+ }
+ size += max;
+ }
+ string_new( buf );
+ string_reserve( buf, size );
+ i = 0;
+ {
+ loop:
+ for ( ; i < length; ++i )
+ {
+ elem[i].size = buf->size;
+ string_append( buf, object_str( list_item( elem[i].elem ) ) );
+ }
+ result = list_push_back( result, object_new( buf->value ) );
+ while ( --i >= 0 )
+ {
+ if( list_next( elem[i].elem ) != list_end( elem[i].saved ) )
+ {
+ elem[i].elem = list_next( elem[i].elem );
+ string_truncate( buf, elem[i].size );
+ goto loop;
+ }
+ else
+ {
+ elem[i].elem = list_begin( elem[i].saved );
+ }
+ }
+ }
+ string_free( buf );
+ return result;
+}
+
+static void combine_strings( STACK * s, int n, string * out )
+{
+ int i;
+ for ( i = 0; i < n; ++i )
+ {
+ LIST * values = stack_pop( s );
+ LISTITER iter = list_begin( values ), 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 ) )
+ {
+ string_push_back( out, ' ' );
+ string_append( out, object_str( list_item( iter ) ) );
+ }
+ list_free( values );
+ }
+ }
+}
+
+struct dynamic_array
+{
+ int size;
+ int capacity;
+ void * data;
+};
+
+static void dynamic_array_init( struct dynamic_array * array )
+{
+ array->size = 0;
+ array->capacity = 0;
+ array->data = 0;
+}
+
+static void dynamic_array_free( struct dynamic_array * array )
+{
+ BJAM_FREE( array->data );
+}
+
+static void dynamic_array_push_impl( struct dynamic_array * array, void * value, int unit_size )
+{
+ if ( array->capacity == 0 )
+ {
+ array->capacity = 2;
+ array->data = BJAM_MALLOC( array->capacity * unit_size );
+ }
+ else if ( array->capacity == array->size )
+ {
+ void * new_data;
+ array->capacity *= 2;
+ new_data = BJAM_MALLOC( array->capacity * unit_size );
+ memcpy( new_data, array->data, array->size * unit_size );
+ BJAM_FREE( array->data );
+ array->data = new_data;
+ }
+ memcpy( (char *)array->data + array->size * unit_size, value, unit_size );
+ ++array->size;
+}
+
+#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
+ */
+
+struct label_info
+{
+ int absolute_position;
+ struct dynamic_array uses[1];
+};
+
+struct stored_rule
+{
+ OBJECT * name;
+ PARSE * parse;
+ int num_arguments;
+ struct arg_list * arguments;
+ int local;
+};
+
+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];
+} compiler;
+
+static void compiler_init( compiler * c )
+{
+ dynamic_array_init( c->code );
+ dynamic_array_init( c->constants );
+ dynamic_array_init( c->labels );
+ dynamic_array_init( c->rules );
+ dynamic_array_init( c->actions );
+}
+
+static void compiler_free( compiler * c )
+{
+ int i;
+ 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( c->labels );
+ dynamic_array_free( c->constants );
+ dynamic_array_free( c->code );
+}
+
+static void compile_emit_instruction( compiler * c, instruction instr )
+{
+ dynamic_array_push( c->code, instr );
+}
+
+static int compile_new_label( compiler * c )
+{
+ int result = c->labels->size;
+ struct label_info info;
+ info.absolute_position = -1;
+ dynamic_array_init( info.uses );
+ dynamic_array_push( c->labels, info );
+ return result;
+}
+
+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;
+ 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);
+ dynamic_array_at( instruction, c->code, id ).arg = offset;
+ }
+}
+
+static void compile_emit( compiler * c, unsigned int op_code, int arg )
+{
+ instruction instr;
+ instr.op_code = op_code;
+ instr.arg = arg;
+ compile_emit_instruction( c, instr );
+}
+
+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;
+ instruction instr;
+ instr.op_code = op_code;
+ if ( l->absolute_position == -1 )
+ {
+ instr.arg = 0;
+ dynamic_array_push( l->uses, pos );
+ }
+ else
+ {
+ instr.arg = (int)( l->absolute_position - pos - 1 );
+ }
+ compile_emit_instruction( c, instr );
+}
+
+static int compile_emit_constant( compiler * c, OBJECT * value )
+{
+ OBJECT * copy = object_copy( value );
+ dynamic_array_push( c->constants, copy );
+ 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 )
+{
+ struct stored_rule rule;
+ rule.name = object_copy( name );
+ rule.parse = parse;
+ rule.num_arguments = num_arguments;
+ rule.arguments = arguments;
+ rule.local = local;
+ dynamic_array_push( c->rules, rule );
+ return (int)( c->rules->size - 1 );
+}
+
+static int compile_emit_actions( compiler * c, PARSE * parse )
+{
+ SUBACTION a;
+ a.name = object_copy( parse->string );
+ 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 );
+}
+
+static JAM_FUNCTION * compile_to_function( compiler * c )
+{
+ JAM_FUNCTION * result = BJAM_MALLOC( sizeof(JAM_FUNCTION) );
+ int i;
+ result->base.type = FUNCTION_JAM;
+ result->base.reference_count = 1;
+ result->base.formal_arguments = 0;
+ result->base.num_formal_arguments = 0;
+
+ 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->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) );
+ 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;
+ }
+
+ 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;
+
+ result->file = 0;
+ result->line = -1;
+
+ return result;
+}
+
+/*
+ * Parsing of variable expansions
+ */
+
+typedef struct VAR_PARSE_GROUP
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_GROUP;
+
+typedef struct VAR_PARSE_ACTIONS
+{
+ struct dynamic_array elems[1];
+} VAR_PARSE_ACTIONS;
+
+#define VAR_PARSE_TYPE_VAR 0
+#define VAR_PARSE_TYPE_STRING 1
+#define VAR_PARSE_TYPE_FILE 2
+
+typedef struct _var_parse
+{
+ int type; /* string or variable */
+} VAR_PARSE;
+
+typedef struct
+{
+ VAR_PARSE base;
+ VAR_PARSE_GROUP * name;
+ VAR_PARSE_GROUP * subscript;
+ struct dynamic_array modifiers[1];
+} VAR_PARSE_VAR;
+
+typedef struct
+{
+ VAR_PARSE base;
+ OBJECT * s;
+} VAR_PARSE_STRING;
+
+typedef struct
+{
+ VAR_PARSE base;
+ 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 ) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_group_free( VAR_PARSE_GROUP * group )
+{
+ 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 );
+}
+
+static void var_parse_group_add( VAR_PARSE_GROUP * group, VAR_PARSE * elem )
+{
+ dynamic_array_push( group->elems, elem );
+}
+
+static void var_parse_group_maybe_add_constant( VAR_PARSE_GROUP * group, const char * start, const char * end )
+{
+ if ( start != end )
+ {
+ string buf[1];
+ VAR_PARSE_STRING * 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 );
+ value->s = object_new( buf->value );
+ string_free( buf );
+ var_parse_group_add( group, (VAR_PARSE *)value );
+ }
+}
+
+VAR_PARSE_STRING * var_parse_group_as_literal( VAR_PARSE_GROUP * group )
+{
+ if ( group->elems->size == 1 )
+ {
+ 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) );
+ dynamic_array_init( result->elems );
+ return result;
+}
+
+static void var_parse_actions_free( VAR_PARSE_ACTIONS * actions )
+{
+ int i;
+ for ( i = 0; i < actions->elems->size; ++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
+ */
+
+static VAR_PARSE_VAR * var_parse_var_new()
+{
+ VAR_PARSE_VAR * result = BJAM_MALLOC( sizeof( VAR_PARSE_VAR ) );
+ result->base.type = VAR_PARSE_TYPE_VAR;
+ result->name = var_parse_group_new();
+ result->subscript = 0;
+ dynamic_array_init( result->modifiers );
+ return result;
+}
+
+static void var_parse_var_free( VAR_PARSE_VAR * var )
+{
+ int i;
+ 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 ) );
+ dynamic_array_free( var->modifiers );
+ BJAM_FREE( var );
+}
+
+static VAR_PARSE_GROUP * var_parse_var_new_modifier( VAR_PARSE_VAR * var )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ dynamic_array_push( var->modifiers, result );
+ return result;
+}
+
+/*
+ * VAR_PARSE_STRING
+ */
+
+static void var_parse_string_free( VAR_PARSE_STRING * string )
+{
+ object_free( string->s );
+ 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 ) );
+ result->base.type = VAR_PARSE_TYPE_FILE;
+ dynamic_array_init( result->filename );
+ dynamic_array_init( result->contents );
+ return result;
+}
+
+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 ) );
+ 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 ) );
+ 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
+ {
+ assert(!"Invalid type");
+ }
+}
+
+/*
+ * Compile VAR_PARSE
+ */
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * parse, compiler * c );
+
+static void var_parse_var_compile( const VAR_PARSE_VAR * parse, compiler * c )
+{
+ int expand_name = 0;
+ /* If there are modifiers, emit them in reverse order. */
+ if ( parse->modifiers->size > 0 )
+ {
+ int i;
+ 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 );
+ }
+ }
+
+ /* If there's 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 ) );
+ 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
+ {
+ var_parse_group_compile( parse->name, c );
+ expand_name = 1;
+ }
+
+ /** 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 )
+ {
+ compile_emit( c, INSTR_PUSH_GROUP, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX, 0 );
+ }
+ else if ( !parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_GROUP, 0 );
+ }
+ if ( parse->modifiers->size && !parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && !parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && !expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS, parse->modifiers->size );
+ }
+ else if ( parse->modifiers->size && parse->subscript && expand_name )
+ {
+ compile_emit( c, INSTR_APPLY_INDEX_MODIFIERS_GROUP, parse->modifiers->size );
+ }
+}
+
+static void var_parse_string_compile( const VAR_PARSE_STRING * parse, compiler * c )
+{
+ 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 )
+{
+ 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 );
+ }
+ 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 );
+ }
+ compile_emit( c, INSTR_WRITE_FILE, parse->contents->size );
+}
+
+static void var_parse_compile( const VAR_PARSE * 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
+ {
+ assert( !"Unknown var parse type." );
+ }
+}
+
+static void var_parse_group_compile( const VAR_PARSE_GROUP * 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. */
+ 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. */
+ 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 )
+{
+ 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 );
+ }
+ 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 );
+
+/*
+ * Parses a string that can contain variables to expand.
+ */
+
+static VAR_PARSE_GROUP * parse_expansion( const char * * string )
+{
+ VAR_PARSE_GROUP * result = var_parse_group_new();
+ const char * s = *string;
+ for (;;)
+ {
+ 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 )
+{
+ VAR_PARSE_ACTIONS * 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.
+ */
+
+static int try_parse_variable( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ const char * s = *s_;
+ if(s[0] == '$' && s[1] == '(')
+ {
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ var_parse_group_add( out, parse_variable( &s ) );
+ *string = s;
+ *s_ = s;
+ return 1;
+ }
+ else if(s[0] == '@' && s[1] == '(')
+ {
+ int depth = 1;
+ const char * ine;
+ const char * split = 0;
+ var_parse_group_maybe_add_constant( out, *string, s );
+ s += 2;
+ ine = s;
+
+ /* Scan the content of the response file @() section. */
+ while ( *ine && ( depth > 0 ) )
+ {
+ switch ( *ine )
+ {
+ case '(': ++depth; break;
+ case ')': --depth; break;
+ case ':':
+ if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
+ split = ine;
+ break;
+ }
+ ++ine;
+ }
+
+ if ( !split || depth != 0 )
+ {
+ return 0;
+ }
+
+ var_parse_group_add( out, parse_at_file( s, split, ine - 1 ) );
+ *string = ine;
+ *s_ = ine;
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+static const char * current_file = "";
+static int current_line;
+
+static void parse_error( const char * 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 "$("
+ */
+
+static VAR_PARSE * parse_variable( const char * * string )
+{
+ VAR_PARSE_VAR * result = var_parse_var_new();
+ VAR_PARSE_GROUP * name = result->name;
+ const char * s = *string;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, name ) ) {}
+ else if ( s[0] == ':' )
+ {
+ VAR_PARSE_GROUP * mod;
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, mod ) ) {}
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, mod );
+ }
+ else if ( s[0] == ':' )
+ {
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ ++s;
+ *string = s;
+ mod = var_parse_var_new_modifier( result );
+ }
+ else if ( s[0] == '[' )
+ {
+ parse_error("unexpected subscript");
+ ++s;
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ var_parse_group_maybe_add_constant( mod, *string, s );
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ }
+ 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;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, subscript ) ) {}
+ 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
+ {
+ parse_error( "unexpected text following []" );
+ break;
+ }
+ }
+ else if ( isdigit( s[0] ) || s[0] == '-' )
+ {
+ ++s;
+ }
+ else if( s[0] == '\0' )
+ {
+ parse_error( "malformed subscript" );
+ break;
+ }
+ else
+ {
+ parse_error( "malformed subscript" );
+ ++s;
+ }
+ }
+ }
+ else if ( s[0] == ')' )
+ {
+ var_parse_group_maybe_add_constant( name, *string, s );
+ ++s;
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else if ( s[0] == '(' )
+ {
+ ++s;
+ balance_parentheses( &s, string, name );
+ }
+ else if ( s[0] == '\0' )
+ {
+ parse_error( "unbalanced parentheses" );
+ var_parse_group_maybe_add_constant( name, *string, s );
+ *string = s;
+ return (VAR_PARSE *)result;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+}
+
+static void parse_var_string( const char * first, const char * last, struct dynamic_array * out )
+{
+ const char * saved = first;
+ for ( ; ; )
+ {
+ /* Handle whitespace */
+ for ( ; first != last; ++first ) if ( !isspace(*first) ) break;
+ if ( saved != first )
+ {
+ VAR_PARSE_GROUP * 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 ) )
+ {
+ var_parse_group_maybe_add_constant( group, saved, first );
+ saved = first;
+ break;
+ }
+ else if ( try_parse_variable( &first, &saved, group ) )
+ {
+ assert( first <= last );
+ }
+ 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 ")".
+ */
+
+static VAR_PARSE * parse_at_file( const char * start, const char * mid, const char * end )
+{
+ VAR_PARSE_FILE * result = var_parse_file_new();
+ parse_var_string( start, mid, result->filename );
+ parse_var_string( mid + 3, end, result->contents );
+ return (VAR_PARSE *)result;
+}
+
+/*
+ * 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.
+ */
+
+void balance_parentheses( const char * * s_, const char * * string, VAR_PARSE_GROUP * out)
+{
+ int depth = 1;
+ const char * s = *s_;
+ for ( ; ; )
+ {
+ if ( try_parse_variable( &s, string, out ) ) { }
+ else if(s[0] == ':' || s[0] == '[')
+ {
+ parse_error( "unbalanced parentheses" );
+ ++s;
+ }
+ else if(s[0] == '\0')
+ {
+ parse_error( "unbalanced parentheses" );
+ break;
+ }
+ else if(s[0] == ')')
+ {
+ ++s;
+ if(--depth == 0) break;
+ }
+ else if(s[0] == '(')
+ {
+ ++depth;
+ ++s;
+ }
+ else
+ {
+ ++s;
+ }
+ }
+ *s_ = s;
+}
+
+/*
+ * Main compile
+ */
+
+#define RESULT_STACK 0
+#define RESULT_RETURN 1
+#define RESULT_NONE 2
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location );
+static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments );
+
+static void compile_condition( PARSE * parse, compiler * c, int branch_true, int label )
+{
+ assert( parse->type == PARSE_EVAL );
+ switch ( parse->num )
+ {
+ 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:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ break;
+ }
+ case EXPR_NOTEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_NE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_EQ, label );
+ break;
+ }
+ case EXPR_LESS:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ break;
+ }
+ case EXPR_LESSEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ break;
+ }
+ case EXPR_MORE:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GT, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LE, label );
+ break;
+ }
+ case EXPR_MOREEQ:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_GE, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_LT, label );
+ break;
+ }
+ case EXPR_IN:
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ if ( branch_true )
+ compile_emit_branch( c, INSTR_JUMP_IN, label );
+ else
+ compile_emit_branch( c, INSTR_JUMP_NOT_IN, label );
+ break;
+ }
+ case EXPR_AND:
+ {
+ if ( branch_true )
+ {
+ int f = compile_new_label( c );
+ compile_condition( parse->left, c, 0, f );
+ compile_condition( parse->right, c, 1, label );
+ compile_set_label( c, f );
+ }
+ else
+ {
+ compile_condition( parse->left, c, 0, label );
+ compile_condition( parse->right, c, 0, label );
+ }
+ break;
+ }
+ case EXPR_OR:
+ {
+ if ( branch_true )
+ {
+ compile_condition( parse->left, c, 1, label );
+ compile_condition( parse->right, c, 1, label );
+ }
+ else
+ {
+ int t = compile_new_label( c );
+ compile_condition( parse->left, c, 1, t );
+ compile_condition( parse->right, c, 0, label );
+ compile_set_label( c, t );
+ }
+ break;
+ }
+ case EXPR_NOT:
+ {
+ compile_condition( parse->left, c, !branch_true, label );
+ break;
+ }
+ }
+}
+
+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 )
+ compile_emit( c, INSTR_POP, 0 );
+ 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 )
+ ;
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_STACK )
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ else if ( actual_location == RESULT_NONE && desired_location == RESULT_RETURN )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_SET_RESULT, 0 );
+ }
+ else
+ {
+ assert( !"invalid result location" );
+ }
+}
+
+static const char * parse_type( PARSE * parse )
+{
+ switch ( parse->type )
+ {
+ case PARSE_APPEND: return "append";
+ case PARSE_EVAL: return "eval";
+ case PARSE_RULES: return "rules";
+ default: return "unknown";
+ }
+}
+
+static void compile_append_chain( PARSE * parse, compiler * c )
+{
+ 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 )
+ compile_append_chain( parse->left, c );
+ else
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_APPEND, 0 );
+ }
+}
+
+static void compile_parse( PARSE * parse, compiler * c, int result_location )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ compile_append_chain( parse, c );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_EVAL )
+ {
+ /* 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 );
+
+ /* Emit the condition */
+ compile_condition( parse, c, 0, f );
+ 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 );
+ compile_set_label( c, end );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ }
+ else if ( parse->type == PARSE_FOREACH )
+ {
+ int var = compile_emit_constant( c, parse->string );
+ int top = compile_new_label( c );
+ int end = compile_new_label( c );
+
+ /*
+ * Evaluate the list.
+ */
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ /* Localize the loop variable */
+ if ( parse->num )
+ {
+ compile_emit( c, INSTR_PUSH_EMPTY, 0 );
+ compile_emit( c, INSTR_PUSH_LOCAL, var );
+ compile_emit( c, INSTR_SWAP, 1 );
+ }
+
+ compile_emit( c, INSTR_FOR_INIT, 0 );
+ 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 );
+
+ compile_emit_branch( c, INSTR_JUMP, top );
+ 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 )
+ {
+ int f = compile_new_label( c );
+ /* Emit the condition */
+ compile_condition( parse->left, c, 0, f );
+ /* Emit the if block */
+ compile_parse( parse->right, c, result_location );
+ if ( parse->third->type != PARSE_NULL || result_location != RESULT_NONE )
+ {
+ /* Emit the else block */
+ int end = compile_new_label( c );
+ compile_emit_branch( c, INSTR_JUMP, end );
+ compile_set_label( c, f );
+ compile_parse( parse->third, c, result_location );
+ compile_set_label( c, end );
+ }
+ else
+ {
+ compile_set_label( c, f );
+ }
+
+ }
+ else if( parse->type == PARSE_WHILE )
+ {
+ 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. */
+ adjust_result( c, RESULT_NONE, nested_result );
+ /* Jump to the loop test */
+ compile_emit_branch( c, INSTR_JUMP, test );
+ compile_set_label( c, top );
+ /* Emit the loop body */
+ compile_parse( parse->right, c, nested_result );
+ /* Emit the condition */
+ compile_set_label( c, test );
+ compile_condition( parse->left, c, 1, top );
+
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_INCLUDE )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_emit( c, INSTR_INCLUDE, 0 );
+ compile_emit( c, INSTR_BIND_MODULE_VARIABLES, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_MODULE )
+ {
+ int 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 );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+ adjust_result( c, nested_result, result_location );
+ }
+ else if ( parse->type == PARSE_CLASS )
+ {
+ /* Evaluate the class name. */
+ 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 );
+ compile_emit( c, INSTR_POP_MODULE, 0 );
+
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_LIST )
+ {
+ OBJECT * o = parse->string;
+ const char * s = object_str( o );
+ VAR_PARSE_GROUP * group;
+ 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 );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ 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
+ */
+ PARSE * vars = parse->left;
+
+ /* Special case an empty list of vars */
+ if ( vars->type == PARSE_NULL )
+ {
+ compile_parse( parse->right, c, RESULT_NONE );
+ compile_parse( parse->third, c, result_location );
+ nested_result = result_location;
+ }
+ /*
+ * 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 );
+ 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 )
+ {
+ int 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 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, INSTR_PUSH_LOCAL_GROUP, 0 );
+ compile_parse( parse->third, c, nested_result );
+ compile_emit( c, INSTR_POP_LOCAL_GROUP, 0 );
+ }
+ adjust_result( c, nested_result, result_location );
+ }
+ 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 );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULE )
+ {
+ PARSE * p;
+ int n = 0;
+ VAR_PARSE_GROUP * group;
+ const char * s = object_str( parse->string );
+
+ if ( parse->left->left == NULL && parse->left->right->type == PARSE_NULL )
+ ;
+ else
+ 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 );
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_RULES )
+ {
+ do compile_parse( parse->left, c, RESULT_NONE );
+ while ( ( parse = parse->right )->type == PARSE_RULES );
+ compile_parse( parse, c, result_location );
+ }
+ else if ( parse->type == PARSE_SET )
+ {
+ PARSE * vars = parse->left;
+ unsigned int op_code;
+ unsigned int op_code_group;
+
+ 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;
+ }
+
+ /*
+ * Check whether there is exactly one variable
+ * with a constant name
+ */
+ if ( vars->type == PARSE_LIST )
+ {
+ const char * 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 )
+ {
+ int 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, op_code, name );
+ }
+ else
+ {
+ var_parse_group_compile( group, c );
+ var_parse_group_free( group );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ }
+ else
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+ compile_emit( c, op_code_group, 0 );
+ }
+ adjust_result( c, RESULT_STACK, 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 );
+
+ 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 );
+
+ compile_parse( parse->left, c, RESULT_STACK );
+
+ compile_emit( c, INSTR_ACTIONS, actions_id );
+ adjust_result( c, RESULT_NONE, result_location );
+ }
+ else if ( parse->type == PARSE_SETTINGS )
+ {
+ compile_parse( parse->left, c, RESULT_STACK );
+ compile_parse( parse->third, c, RESULT_STACK );
+ compile_parse( parse->right, c, RESULT_STACK );
+
+ 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;
+ }
+
+ adjust_result( c, RESULT_STACK, result_location );
+ }
+ else if ( parse->type == PARSE_SWITCH )
+ {
+ int 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 );
+ 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 );
+ compile_emit_branch( c, INSTR_JUMP, switch_end );
+ compile_set_label( c, next_case );
+ }
+ compile_emit( c, INSTR_POP, 0 );
+ adjust_result( c, RESULT_NONE, result_location );
+ 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 )
+{
+ return function->rulename;
+}
+
+void function_set_rulename( FUNCTION * function, OBJECT * rulename )
+{
+ function->rulename = rulename;
+}
+
+void function_location( FUNCTION * function_, OBJECT * * file, int * line )
+{
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#ifdef HAVE_PYTHON
+ if ( function_->type == FUNCTION_PYTHON )
+ {
+ *file = constant_builtin;
+ *line = -1;
+ }
+#endif
+ else
+ {
+ JAM_FUNCTION * function = (JAM_FUNCTION *)function_;
+ assert( function_->type == FUNCTION_JAM );
+ *file = function->file;
+ *line = function->line;
+ }
+}
+
+static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments );
+
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * 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->func = func;
+ result->flags = flags;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile( PARSE * parse )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ compiler_init( c );
+ compile_parse( parse, c, RESULT_RETURN );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( parse->file );
+ result->line = parse->line;
+ return (FUNCTION *)result;
+}
+
+FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line )
+{
+ compiler c[1];
+ JAM_FUNCTION * result;
+ VAR_PARSE_ACTIONS * parse;
+ current_file = object_str( file );
+ current_line = line;
+ parse = parse_actions( actions );
+ compiler_init( c );
+ var_parse_actions_compile( parse, c );
+ var_parse_actions_free( parse );
+ compile_emit( c, INSTR_RETURN, 0 );
+ result = compile_to_function( c );
+ compiler_free( c );
+ result->file = object_copy( file );
+ result->line = line;
+ return (FUNCTION *)result;
+}
+
+static void argument_list_print( struct arg_list * args, int num_args );
+
+
+/* Define delimiters for type check elements in argument lists (and return type
+ * specifications, eventually).
+ */
+# define TYPE_OPEN_DELIM '['
+# define TYPE_CLOSE_DELIM ']'
+
+/*
+ * is_type_name() - true iff the given string represents a type check
+ * specification.
+ */
+
+int is_type_name( const char * s )
+{
+ 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 * );
+ 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 );
+ printf( " )\n* called with: ( " );
+ lol_print( actual );
+ printf( " )\n* %s %s\n", message, arg ? object_str ( arg ) : "" );
+ function_location( procedure, &frame->file, &frame->line );
+ print_source_line( frame );
+ printf( "see definition of rule '%s' being called\n", frame->rulename );
+ backtrace( frame->prev );
+ exit( 1 );
+}
+
+static void type_check_range
+(
+ OBJECT * type_name,
+ LISTITER iter,
+ LISTITER end,
+ FRAME * caller,
+ FUNCTION * called,
+ OBJECT * arg_name
+)
+{
+ static module_t * typecheck = 0;
+
+ /* If nothing to check, bail now. */
+ if ( iter == end || !type_name )
+ 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 ) )
+ return;
+
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ 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;
+
+ /* Prepare the argument list */
+ lol_add( frame->args, list_new( object_copy( list_item( iter ) ) ) );
+ error = evaluate_rule( type_name, frame );
+
+ if ( !list_empty( error ) )
+ 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
+)
+{
+ 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 )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ 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 )
+ {
+ 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 );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ 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 );
+ /* fallthrough */
+ case ARG_STAR:
+ 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:
+ return;
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ 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 ) );
+ }
+ }
+}
+
+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;
+
+ 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 )
+ {
+ 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 );
+ value = list_new( object_copy( list_item( actual_iter ) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ value = L0;
+ else
+ {
+ value = list_new( object_copy( 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 );
+ /* fallthrough */
+ case ARG_STAR:
+ value = list_copy_range( actual, actual_iter, actual_end );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ 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 ];
+ stack_push( s, *old );
+ *old = value;
+ }
+ else
+ {
+ 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 ) );
+ }
+ }
+
+ 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 ) );
+ }
+ }
+}
+
+void argument_list_pop( struct arg_list * formal, int formal_count, FRAME * frame, STACK * s )
+{
+ int i, j;
+
+ for ( i = formal_count - 1; i >= 0; --i )
+ {
+ for ( j = formal[i].size - 1; j >= 0 ; --j )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+
+ if ( formal_arg->flags == ARG_VARIADIC )
+ {
+ continue;
+ }
+ else if ( formal_arg->index != -1 )
+ {
+ LIST * old = stack_pop( s );
+ LIST * * 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 );
+ }
+ }
+ }
+}
+
+
+struct argument_compiler
+{
+ struct dynamic_array args[ 1 ];
+ struct argument arg;
+ int state;
+#define ARGUMENT_COMPILER_START 0
+#define ARGUMENT_COMPILER_FOUND_TYPE 1
+#define ARGUMENT_COMPILER_FOUND_OBJECT 2
+#define ARGUMENT_COMPILER_DONE 3
+};
+
+
+static void argument_compiler_init( struct argument_compiler * c )
+{
+ dynamic_array_init( c->args );
+ c->state = ARGUMENT_COMPILER_START;
+}
+
+static void argument_compiler_free( struct argument_compiler * c )
+{
+ dynamic_array_free( c->args );
+}
+
+static void argument_compiler_add( struct argument_compiler * c, OBJECT * arg, OBJECT * file, int line )
+{
+ switch ( c->state )
+ {
+ case ARGUMENT_COMPILER_FOUND_OBJECT:
+
+ if ( object_equal( arg, constant_question_mark ) )
+ {
+ c->arg.flags = ARG_OPTIONAL;
+ }
+ else if ( object_equal( arg, constant_plus ) )
+ {
+ c->arg.flags = ARG_PLUS;
+ }
+ else if ( object_equal( arg, constant_star ) )
+ {
+ c->arg.flags = ARG_STAR;
+ }
+
+ dynamic_array_push( c->args, c->arg );
+ c->state = ARGUMENT_COMPILER_START;
+
+ if ( c->arg.flags != ARG_ONE )
+ break;
+ /* fall-through */
+
+ case ARGUMENT_COMPILER_START:
+
+ c->arg.type_name = 0;
+ c->arg.index = -1;
+ c->arg.flags = ARG_ONE;
+
+ if ( is_type_name( object_str( arg ) ) )
+ {
+ c->arg.type_name = object_copy( arg );
+ c->state = ARGUMENT_COMPILER_FOUND_TYPE;
+ break;
+ }
+ /* 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 ) );
+ exit( 1 );
+ }
+
+ c->arg.arg_name = object_copy( arg );
+ if ( object_equal( arg, constant_star ) )
+ {
+ c->arg.flags = ARG_VARIADIC;
+ dynamic_array_push( c->args, c->arg );
+ c->state = ARGUMENT_COMPILER_DONE;
+ }
+ else
+ {
+ c->state = ARGUMENT_COMPILER_FOUND_OBJECT;
+ }
+ break;
+
+ case ARGUMENT_COMPILER_DONE:
+ break;
+ }
+}
+
+static void argument_compiler_recurse( struct argument_compiler * c, PARSE * parse )
+{
+ if ( parse->type == PARSE_APPEND )
+ {
+ argument_compiler_recurse( c, parse->left );
+ argument_compiler_recurse( c, parse->right );
+ }
+ else if ( parse->type != PARSE_NULL )
+ {
+ assert( parse->type == PARSE_LIST );
+ argument_compiler_add( c, parse->string, parse->file, parse->line );
+ }
+}
+
+static struct arg_list arg_compile_impl( struct argument_compiler * c, OBJECT * file, int line )
+{
+ struct arg_list result;
+ switch ( c->state )
+ {
+ case ARGUMENT_COMPILER_START:
+ 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 ) );
+ exit( 1 );
+ case ARGUMENT_COMPILER_FOUND_OBJECT:
+ dynamic_array_push( c->args, c->arg );
+ break;
+ }
+ 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 ) );
+ return result;
+}
+
+static struct arg_list arg_compile( PARSE * parse )
+{
+ struct argument_compiler c[ 1 ];
+ struct arg_list result;
+ argument_compiler_init( c );
+ argument_compiler_recurse( c, parse );
+ result = arg_compile_impl( c, parse->file, parse->line );
+ argument_compiler_free( c );
+ return result;
+}
+
+struct argument_list_compiler
+{
+ struct dynamic_array args[ 1 ];
+};
+
+static void argument_list_compiler_init( struct argument_list_compiler * c )
+{
+ dynamic_array_init( c->args );
+}
+
+static void argument_list_compiler_free( struct argument_list_compiler * c )
+{
+ dynamic_array_free( c->args );
+}
+
+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 )
+{
+ if ( parse )
+ {
+ argument_list_compiler_add( c, parse->right );
+ argument_list_compiler_recurse( c, parse->left );
+ }
+}
+
+static struct arg_list * arg_list_compile( PARSE * parse, int * num_arguments )
+{
+ if ( parse )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ argument_list_compiler_init( c );
+ 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 ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+static struct arg_list * arg_list_compile_builtin( const char * * args, int * num_arguments )
+{
+ if ( args )
+ {
+ struct argument_list_compiler c[ 1 ];
+ struct arg_list * result;
+ argument_list_compiler_init( c );
+ while ( *args )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ argument_compiler_init( arg_comp );
+ for ( ; *args; ++args )
+ {
+ OBJECT * token;
+ if ( strcmp( *args, ":" ) == 0 )
+ {
+ ++args;
+ break;
+ }
+ token = object_new( *args );
+ argument_compiler_add( arg_comp, token, constant_builtin, -1 );
+ object_free( token );
+ }
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ }
+ *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 ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *num_arguments = 0;
+ return 0;
+ }
+}
+
+static void argument_list_print( struct arg_list * args, int num_args )
+{
+ if ( args )
+ {
+ int i, j;
+ for ( i = 0; i < num_args; ++i )
+ {
+ 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 )
+ {
+ case ARG_OPTIONAL: printf( " ?" ); break;
+ case ARG_PLUS: printf( " +" ); break;
+ case ARG_STAR: printf( " *" ); break;
+ }
+ }
+ }
+ }
+}
+
+
+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;
+
+ for ( i = 0; i < formal_count; ++i )
+ {
+ 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 ];
+ if ( args[ j ].type_name )
+ 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 );
+ }
+ }
+ result[ i ].args = args;
+ result[ i ].size = formal[ i ].size;
+ }
+
+ return result;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+void argument_list_free( struct arg_list * args, int args_count )
+{
+ int i, j;
+ for ( i = 0; i < args_count; ++i )
+ {
+ for ( j = 0; j < args[ i ].size; ++j )
+ {
+ if ( args[ i ].args[ j ].type_name )
+ object_free( args[ i ].args[ j ].type_name );
+ object_free( args[ i ].args[ j ].arg_name );
+ }
+ BJAM_FREE( args[ i ].args );
+ }
+ BJAM_FREE( args );
+}
+
+
+FUNCTION * function_unbind_variables( FUNCTION * f )
+{
+ if ( f->type == FUNCTION_JAM )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ if ( func->generic )
+ return func->generic;
+ else
+ return (FUNCTION *)func;
+ }
+#ifdef HAVE_PYTHON
+ else if ( f->type == FUNCTION_PYTHON )
+ {
+ return f;
+ }
+#endif
+ else
+ {
+ assert( f->type == FUNCTION_BUILTIN );
+ return f;
+ }
+}
+
+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 )
+ {
+ return f;
+ }
+#endif
+ else
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)f;
+ JAM_FUNCTION * new_func = BJAM_MALLOC( sizeof( JAM_FUNCTION ) );
+ instruction * code;
+ int i;
+ 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->code = BJAM_MALLOC( 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 )
+ {
+ OBJECT * key;
+ int op_code;
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_VAR: op_code = INSTR_PUSH_VAR_FIXED; break;
+ case INSTR_PUSH_LOCAL: op_code = INSTR_PUSH_LOCAL_FIXED; break;
+ case INSTR_POP_LOCAL: op_code = INSTR_POP_LOCAL_FIXED; break;
+ case INSTR_SET: op_code = INSTR_SET_FIXED; break;
+ 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_RULE: ++i; continue;
+ case INSTR_PUSH_MODULE:
+ {
+ int depth = 1;
+ ++i;
+ while ( depth > 0 )
+ {
+ code = func->code + i;
+ switch ( code->op_code )
+ {
+ case INSTR_PUSH_MODULE:
+ case INSTR_CLASS:
+ ++depth;
+ break;
+ case INSTR_POP_MODULE:
+ --depth;
+ break;
+ case INSTR_CALL_RULE:
+ ++i;
+ break;
+ }
+ ++i;
+ }
+ --i;
+ }
+ default: continue;
+ }
+ key = func->constants[ code->arg ];
+ if ( !( object_equal( key, constant_TMPDIR ) ||
+ object_equal( key, constant_TMPNAME ) ||
+ object_equal( key, constant_TMPFILE ) ||
+ object_equal( key, constant_STDOUT ) ||
+ object_equal( key, constant_STDERR ) ) )
+ {
+ code->op_code = op_code;
+ code->arg = module_add_fixed_var( module, key, counter );
+ }
+ }
+ }
+}
+
+void function_refer( FUNCTION * func )
+{
+ ++func->reference_count;
+}
+
+void function_free( FUNCTION * function_ )
+{
+ int i;
+
+ 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 )
+ {
+ JAM_FUNCTION * func = (JAM_FUNCTION *)function_;
+
+ BJAM_FREE( func->code );
+
+ if ( func->generic )
+ function_free( func->generic );
+ else
+ {
+ if ( function_->rulename ) object_free( function_->rulename );
+
+ for ( i = 0; i < func->num_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 );
+ }
+ BJAM_FREE( func->functions );
+
+ for ( i = 0; i < func->num_subactions; ++i )
+ {
+ object_free( func->actions[i].name );
+ function_free( func->actions[i].command );
+ }
+ BJAM_FREE( func->actions );
+
+ object_free( func->file );
+ }
+ }
+#ifdef HAVE_PYTHON
+ else if ( function_->type == FUNCTION_PYTHON )
+ {
+ PYTHON_FUNCTION * func = (PYTHON_FUNCTION *)function_;
+ Py_DECREF( func->python_function );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+#endif
+ else
+ {
+ assert( function_->type == FUNCTION_BUILTIN );
+ if ( function_->rulename ) object_free( function_->rulename );
+ }
+
+ BJAM_FREE( function_ );
+}
+
+
+/* Alignment check for stack */
+
+struct align_var_edits
+{
+ char ch;
+ VAR_EDITS e;
+};
+
+struct align_expansion_item
+{
+ char ch;
+ expansion_item e;
+};
+
+static char check_align_var_edits[ sizeof(struct align_var_edits) <= sizeof(VAR_EDITS) + sizeof(void *) ? 1 : -1 ];
+static char check_align_expansion_item[ sizeof(struct align_expansion_item) <= sizeof(expansion_item) + sizeof(void *) ? 1 : -1 ];
+
+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 )
+{
+ *(string * *)stack_allocate( s, sizeof( string * ) ) = out;
+ list_free( function_run( function, frame, s ) );
+ stack_deallocate( s, sizeof( string * ) );
+}
+
+/*
+ * 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 )
+{
+ JAM_FUNCTION * function;
+ instruction * code;
+ LIST * l;
+ LIST * r;
+ LIST * result = L0;
+ void * saved_stack = s->data;
+
+ if ( function_->type == FUNCTION_BUILTIN )
+ {
+ BUILTIN_FUNCTION * f = (BUILTIN_FUNCTION *)function_;
+ if ( function_->formal_arguments )
+ 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 );
+
+ function = (JAM_FUNCTION *)function_;
+ code = function->code;
+ for ( ; ; )
+ {
+ switch ( code->op_code )
+ {
+
+ /*
+ * Basic stack manipulation
+ */
+
+ case INSTR_PUSH_EMPTY:
+ {
+ stack_push( s, L0 );
+ break;
+ }
+
+ case INSTR_PUSH_CONSTANT:
+ {
+ OBJECT * value = function_get_constant( function, code->arg );
+ stack_push( s, list_new( object_copy( value ) ) );
+ break;
+ }
+
+ 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 ] ) );
+ break;
+ }
+
+ case INSTR_PUSH_GROUP:
+ {
+ LIST * value = L0;
+ LISTITER iter, 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 );
+ }
+ 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; }
+ list_free( l );
+ break;
+ }
+
+ case INSTR_JUMP_NOT_EMPTY:
+ {
+ l = stack_pop( s );
+ 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; }
+ 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; }
+ 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; }
+ 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; }
+ 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; }
+ 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; }
+ 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; }
+ 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; }
+ 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 ) )
+ {
+ list_free( stack_pop( s ) );
+ code += code->arg;
+ }
+ else
+ {
+ r = list_new( object_copy( list_item( iter ) ) );
+ iter = list_next( iter );
+ *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) = iter;
+ stack_push( s, r );
+ }
+ break;
+ }
+
+ /*
+ * Switch
+ */
+
+ case INSTR_JUMP_NOT_GLOB:
+ {
+ const char * pattern;
+ const char * 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 ) )
+ {
+ code += code->arg;
+ }
+ else
+ {
+ list_free( stack_pop( s ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * Return
+ */
+
+ case INSTR_SET_RESULT:
+ {
+ list_free( result );
+ result = stack_pop( 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 );
+#ifndef NDEBUG
+
+ if ( !( saved_stack == s->data ) )
+ {
+ frame->file = function->file;
+ frame->line = function->line;
+ backtrace_line( frame );
+ printf( "error: stack check failed.\n" );
+ backtrace( frame );
+ assert( saved_stack == s->data );
+ }
+#endif
+ assert( saved_stack == s->data );
+ return result;
+ }
+
+ /*
+ * Local variables
+ */
+
+ case INSTR_PUSH_LOCAL:
+ {
+ LIST * value = stack_pop( s );
+ 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:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ stack_push( s, *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_POP_LOCAL_FIXED:
+ {
+ LIST * value = stack_pop( s );
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ list_free( *ptr );
+ *ptr = value;
+ break;
+ }
+
+ case INSTR_PUSH_LOCAL_GROUP:
+ {
+ LIST * value = stack_pop( s );
+ LISTITER iter, 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 );
+ }
+ list_free( value );
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_POP_LOCAL_GROUP:
+ {
+ LISTITER iter, 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 ) );
+ }
+ list_free( l );
+ break;
+ }
+
+ /*
+ * on $(TARGET) variables
+ */
+
+ case INSTR_PUSH_ON:
+ {
+ LIST * targets = stack_top( s );
+ if ( !list_empty( targets ) )
+ {
+ /*
+ * 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.
+ */
+ list_free( stack_pop( s ) );
+ stack_push( s, L0 );
+ code += code->arg;
+ }
+ break;
+ }
+
+ case INSTR_POP_ON:
+ {
+ LIST * result = stack_pop( s );
+ LIST * targets = stack_pop( s );
+ if ( !list_empty( targets ) )
+ {
+ TARGET * t = bindtarget( list_front( targets ) );
+ popsettings( frame->module, t->settings );
+ }
+ list_free( targets );
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_SET_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), 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 ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), 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 ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_ON:
+ {
+ LIST * targets = stack_pop( s );
+ LIST * value = stack_pop( s );
+ LIST * vars = stack_pop( s );
+ LISTITER iter = list_begin( targets ), 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 ) );
+ }
+ list_free( vars );
+ list_free( targets );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Variable setting
+ */
+
+ case INSTR_SET:
+ {
+ function_set_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_APPEND:
+ {
+ function_append_variable( function, frame, code->arg, list_copy( stack_top( s ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT:
+ {
+ function_default_variable( function, frame, code->arg, list_copy( stack_top( 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 ) );
+ break;
+ }
+
+ case INSTR_APPEND_FIXED:
+ {
+ 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 ) ) );
+ break;
+ }
+
+ case INSTR_DEFAULT_FIXED:
+ {
+ LIST * * ptr = &frame->module->fixed_variables[ code->arg ];
+ assert( code->arg < frame->module->num_fixed_variables );
+ if ( list_empty( *ptr ) )
+ *ptr = list_copy( stack_top( s ) );
+ break;
+ }
+
+ case INSTR_SET_GROUP:
+ {
+ 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 ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_APPEND_GROUP:
+ {
+ 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 ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ case INSTR_DEFAULT_GROUP:
+ {
+ 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 ) );
+ list_free( vars );
+ stack_push( s, value );
+ break;
+ }
+
+ /*
+ * Rules
+ */
+
+ 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 );
+ 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
+ */
+
+ case INSTR_APPLY_MODIFIERS:
+ {
+ int n;
+ int i;
+ l = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, l );
+ l = apply_modifiers( s, n );
+ 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 */
+ 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;
+ int n;
+ l = stack_pop( s );
+ r = stack_pop( s );
+ n = expand_modifiers( s, code->arg );
+ stack_push( s, r );
+ stack_push( s, l );
+ l = apply_subscript_and_modifiers( s, n );
+ list_free( stack_pop( s ) );
+ 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 */
+ stack_push( s, l );
+ break;
+ }
+
+ case INSTR_APPLY_MODIFIERS_GROUP:
+ {
+ int i;
+ LIST * vars = stack_pop( s );
+ int 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 ) )
+ {
+ 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 */
+ 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 ) )
+ {
+ stack_push( s, function_get_named_variable( function, frame, list_item( iter ) ) );
+ result = list_append( result, apply_subscript( s ) );
+ list_free( stack_pop( s ) );
+ }
+ list_free( vars );
+ list_free( stack_pop( s ) );
+ 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 * result = L0;
+ LISTITER iter = list_begin( vars ), end = list_end( vars );
+ stack_push( s, r );
+ 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 ) );
+ 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 */
+ 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 );
+ expansion_item * items = stack_allocate( s, buffer_size );
+ int i;
+ for( i = 0; i < code->arg; ++i )
+ {
+ items[i].saved = stack_pos[i];
+ items[i].elem = list_begin( items[i].saved );
+ }
+ result = expand( items, code->arg );
+ stack_deallocate( s, buffer_size );
+ for( i = 0; i < code->arg; ++i )
+ {
+ list_free( stack_pop( s ) );
+ }
+ stack_push( s, result );
+ break;
+ }
+
+ case INSTR_INCLUDE:
+ {
+ LIST * nt = stack_pop( s );
+
+ if ( !list_empty( nt ) )
+ {
+ TARGET * 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.
+ */
+
+ /* 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. */
+ object_free( t->boundname );
+ t->boundname = search( t->name, &t->time, 0, 0 );
+ popsettings( root_module(), t->settings );
+
+ parse_file( t->boundname, frame );
+ }
+
+ break;
+ }
+
+ /*
+ * Classes and modules
+ */
+
+ 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_free( module_name );
+
+ *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module;
+
+ break;
+ }
+
+ case INSTR_POP_MODULE:
+ {
+ module_t * outer_module = *(module_t * *)stack_get( s );
+ stack_deallocate( s, sizeof( module_t * ) );
+ frame->module = outer_module;
+ break;
+ }
+
+ case INSTR_CLASS:
+ {
+ LIST * bases = stack_pop( s );
+ LIST * name = stack_pop( s );
+ OBJECT * class_module = make_class_module( name, bases, frame );
+
+ module_t * outer_module = frame->module;
+ frame->module = bindmodule( class_module );
+ object_free( class_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_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;
+ OBJECT * tmp_filename = 0;
+ int out_debug = DEBUG_EXEC ? 1 : 0;
+ FILE * out_file = 0;
+ string_new( buf );
+ 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.
+ */
+ if ( ( strcmp( "STDOUT", out ) == 0 ) ||
+ ( strcmp( "STDERR", out ) == 0 ) )
+ {
+ int err_redir = strcmp( "STDERR", out ) == 0;
+ string result[1];
+ tmp_filename = path_tmpfile();
+ string_new( result );
+
+ #ifdef OS_NT
+ string_append( result, "type \"" );
+ #else
+ string_append( result, "cat \"" );
+ #endif
+ string_append( result, object_str( tmp_filename ) );
+ string_push_back( result, '\"' );
+ if ( err_redir )
+ string_append( result, " 1>&2" );
+
+ /* Replace STDXXX with the temporary file. */
+ list_free( stack_pop( s ) );
+ stack_push( s, list_new( object_new( result->value ) ) );
+ out = object_str( tmp_filename );
+
+ string_free( result );
+
+ /* We also make sure that the temp files created by this
+ * get nuked eventually.
+ */
+ file_remove_atexit( tmp_filename );
+ }
+
+ if ( !globs.noexec )
+ {
+ string out_name[1];
+ /* Handle "path to file" filenames. */
+ 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 );
+ 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 );
+ fclose( out_file );
+ }
+ string_free( buf );
+ if ( tmp_filename )
+ 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 * ) ) );
+ combine_strings( s, code->arg, buf );
+ break;
+ }
+
+ }
+ ++code;
+ }
+}
+
+
+#ifdef HAVE_PYTHON
+
+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;
+ argument_list_compiler_init( c );
+
+ s = PySequence_Size( bjam_signature );
+ for ( i = 0; i < s; ++i )
+ {
+ struct argument_compiler arg_comp[ 1 ];
+ struct arg_list arg;
+ PyObject * v = PySequence_GetItem( bjam_signature, i );
+ 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 );
+ }
+
+ arg = arg_compile_impl( arg_comp, constant_builtin, -1 );
+ dynamic_array_push( c->args, arg );
+ argument_compiler_free( arg_comp );
+ Py_DECREF( v );
+ }
+
+ *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 ) );
+ argument_list_compiler_free( c );
+ return result;
+ }
+ else
+ {
+ *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 );
+ 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 )
+{
+ LOL * all_actual = frame->args;
+ int i, j;
+
+ 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 )
+ {
+ struct argument * formal_arg = &formal[i].args[j];
+ PyObject * value;
+ LIST * l;
+
+ 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 );
+ value = PyString_FromString( object_str( list_item( actual_iter) ) );
+ actual_iter = list_next( actual_iter );
+ break;
+ case ARG_OPTIONAL:
+ if ( actual_iter == actual_end )
+ 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) ) );
+ 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 );
+ /* fallthrough */
+ case ARG_STAR:
+ 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 );
+ actual_iter = actual_end;
+ break;
+ case ARG_VARIADIC:
+ return;
+ }
+
+ if (value)
+ {
+ PyObject * key = PyString_FromString( object_str( formal_arg->arg_name ) );
+ PyDict_SetItem( kw, key, value );
+ Py_DECREF( key );
+ Py_DECREF( value );
+ }
+ }
+
+ if ( actual_iter != actual_end )
+ {
+ 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 ) );
+ }
+ }
+}
+
+/* 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. */
+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 0;
+ }
+}
+
+static module_t * python_module()
+{
+ static module_t * python = 0;
+ if ( !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 ;
+ PyObject * py_result;
+ FRAME * prev_frame_before_python_call;
+
+ if ( function->base.formal_arguments )
+ {
+ arguments = PyTuple_New(0);
+ kw = PyDict_New();
+
+ 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 ) ) );
+ }
+ }
+
+ frame->module = python_module();
+
+ prev_frame_before_python_call = frame_before_python_call;
+ frame_before_python_call = frame;
+ py_result = PyObject_Call( function->python_function, arguments, kw );
+ frame_before_python_call = prev_frame_before_python_call;
+ Py_DECREF( arguments );
+ Py_XDECREF( kw );
+ if ( py_result != NULL )
+ {
+ if ( PyList_Check( py_result ) )
+ {
+ int size = PyList_Size( py_result );
+ 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 {
+ result = list_push_back( result, s );
+ }
+ }
+ }
+ else if ( py_result == Py_None )
+ {
+ result = L0;
+ }
+ else
+ {
+ OBJECT *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;
+ }
+
+ Py_DECREF( py_result );
+ }
+ else
+ {
+ PyErr_Print();
+ fprintf( stderr,"Call failed\n" );
+ }
+
+ return result;
+}
+
+#endif
+
+
+void function_done( void )
+{
+ BJAM_FREE( stack );
+}
diff --git a/tools/build/v2/engine/function.h b/tools/build/v2/engine/function.h
new file mode 100644
index 0000000000..64f26b3cf7
--- /dev/null
+++ b/tools/build/v2/engine/function.h
@@ -0,0 +1,46 @@
+/*
+ * 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)
+ */
+
+#ifndef FUNCTION_SW20111123_H
+#define FUNCTION_SW20111123_H
+
+#include "object.h"
+#include "frames.h"
+#include "lists.h"
+#include "parse.h"
+#include "strings.h"
+
+typedef struct _function FUNCTION;
+typedef struct _stack STACK;
+
+STACK * stack_global( void );
+void stack_push( STACK * s, LIST * l );
+LIST * stack_pop( STACK * s );
+
+FUNCTION * function_compile( PARSE * parse );
+FUNCTION * function_builtin( LIST * ( * func )( FRAME * frame, int flags ), int flags, const char * * args );
+void function_refer( FUNCTION * );
+void function_free( FUNCTION * );
+OBJECT * function_rulename( FUNCTION * );
+void function_set_rulename( FUNCTION *, OBJECT * );
+void function_location( FUNCTION *, OBJECT * *, int * );
+LIST * function_run( FUNCTION * function, FRAME * frame, STACK * s );
+
+FUNCTION * function_compile_actions( const char * actions, OBJECT * file, int line );
+void function_run_actions( FUNCTION * function, FRAME * frame, STACK * s, string * out );
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+void function_done( void );
+
+#ifdef HAVE_PYTHON
+
+FUNCTION * function_python( PyObject * function, PyObject * bjam_signature );
+
+#endif
+
+#endif
diff --git a/tools/build/v2/engine/glob.c b/tools/build/v2/engine/glob.c
index 527d6c8088..bec00ee562 100644
--- a/tools/build/v2/engine/glob.c
+++ b/tools/build/v2/engine/glob.c
@@ -29,17 +29,17 @@
# define CHECK_BIT( tab, bit ) ( tab[ (bit)/8 ] & (1<<( (bit)%8 )) )
# define BITLISTSIZE 16 /* bytes used for [chars] in compiled expr */
-static void globchars( char * s, char * e, char * b );
+static void globchars( const char * s, const char * e, char * b );
/*
* glob() - match a string against a simple pattern.
*/
-int glob( char * c, char * s )
+int glob( const char * c, const char * s )
{
char bitlist[ BITLISTSIZE ];
- char * here;
+ const char * here;
for ( ; ; )
switch ( *c++ )
@@ -64,7 +64,7 @@ int glob( char * c, char * s )
globchars( here, c, bitlist );
- if ( !CHECK_BIT( bitlist, *(unsigned char *)s ) )
+ if ( !CHECK_BIT( bitlist, *(const unsigned char *)s ) )
return 1;
++s;
break;
@@ -111,7 +111,7 @@ int glob( char * c, char * s )
* globchars() - build a bitlist to check for character group match.
*/
-static void globchars( char * s, char * e, char * b )
+static void globchars( const char * s, const char * e, char * b )
{
int neg = 0;
diff --git a/tools/build/v2/engine/hash.c b/tools/build/v2/engine/hash.c
index fbd1a8993d..6e748ab4d0 100644
--- a/tools/build/v2/engine/hash.c
+++ b/tools/build/v2/engine/hash.c
@@ -7,6 +7,7 @@
# include "jam.h"
# include "hash.h"
# include "compile.h"
+# include "object.h"
# include <assert.h>
/*
@@ -29,30 +30,16 @@
#define HASH_DEBUG_PROFILE 1
/* */
-char *hashsccssid="@(#)hash.c 1.14 () 6/20/88";
-
/* Header attached to all data items entered into a hash table. */
struct hashhdr
{
struct item * next;
- unsigned int keyval; /* for quick comparisons */
-};
-
-/* This structure overlays the one handed to hashenter(). Its actual size is
- * given to hashinit().
- */
-
-struct hashdata
-{
- char * key;
- /* rest of user data */
};
typedef struct item
{
struct hashhdr hdr;
- struct hashdata data;
} ITEM ;
# define MAX_LISTS 32
@@ -78,7 +65,6 @@ struct hash
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 datalen; /* length of records in this hash table */
int size; /* sizeof( ITEM ) + aligned datalen */
int nel; /* total ITEMs held by all lists[] */
int list; /* index into lists[] */
@@ -89,54 +75,23 @@ struct hash
} lists[ MAX_LISTS ];
} items;
- char * name; /* just for hashstats() */
+ const char * name; /* just for hashstats() */
};
static void hashrehash( struct hash *hp );
static void hashstat( struct hash *hp );
-static void * hash_mem_alloc(size_t datalen, size_t size);
-static void hash_mem_free(size_t datalen, void * data);
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(char * key, struct hash * hp);
-#endif
-
-static unsigned int jenkins_one_at_a_time_hash(const unsigned char *key)
-{
- unsigned int hash = 0;
-
- while ( *key )
- {
- hash += *key++;
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
- hash += (hash << 3);
- hash ^= (hash >> 11);
- hash += (hash << 15);
-
- return hash;
-}
-
-/*
-static unsigned int knuth_hash(const unsigned char *key)
-{
- unsigned int keyval = *key;
- while ( *key )
- keyval = keyval * 2147059363 + *key++;
- return keyval;
-}
-*/
-static unsigned int hash_keyval( const char * key_ )
+static unsigned int hash_keyval( OBJECT * key )
{
- /*
- return knuth_hash((const unsigned char *)key_);
- */
- return jenkins_one_at_a_time_hash((const unsigned char *)key_);
+ return object_hash( key );
}
#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_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,
@@ -145,7 +100,7 @@ static unsigned int hash_keyval( const char * key_ )
static ITEM * hash_search(
struct hash *hp,
unsigned int keyval,
- const char * keydata,
+ OBJECT * keydata,
ITEM * * previous )
{
ITEM * i = *hash_bucket(hp,keyval);
@@ -153,8 +108,7 @@ static ITEM * hash_search(
for ( ; i; i = i->hdr.next )
{
- if ( ( keyval == i->hdr.keyval ) &&
- !strcmp( i->data.key, keydata ) )
+ if ( object_equal( hash_item_key( i ), keydata ) )
{
if (previous)
{
@@ -169,52 +123,13 @@ static ITEM * hash_search(
}
/*
- * hash_free() - remove the given item from the table if it's there.
- * Returns 1 if found, 0 otherwise.
- *
- * NOTE: 2nd argument is HASHDATA*, not HASHDATA** as elsewhere.
- */
-int
-hash_free(
- register struct hash *hp,
- HASHDATA *data)
-{
- ITEM * i = 0;
- ITEM * prev = 0;
- unsigned int keyval = hash_keyval(data->key);
-
- i = hash_search( hp, keyval, data->key, &prev );
- if (i)
- {
- /* mark it free so we skip it during enumeration */
- i->data.key = 0;
- /* unlink the record from the hash chain */
- if (prev) prev->hdr.next = i->hdr.next;
- else *hash_bucket(hp,keyval) = i->hdr.next;
- /* link it into the freelist */
- i->hdr.next = hp->items.free;
- hp->items.free = i;
- /* we have another item */
- hp->items.more++;
-
- return 1;
- }
- return 0;
-}
-
-/*
- * hashitem() - find a record in the table, and optionally enter a new one
+ * hash_insert() - insert a record in the table or return the existing one
*/
-int
-hashitem(
- register struct hash *hp,
- HASHDATA **data,
- int enter )
+HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
{
- register ITEM *i;
- char *b = (*data)->key;
- unsigned int keyval = hash_keyval(b);
+ ITEM * i;
+ unsigned int keyval = hash_keyval( key );
#ifdef HASH_DEBUG_PROFILE
profile_frame prof[1];
@@ -222,38 +137,24 @@ hashitem(
profile_enter( 0, prof );
#endif
- if ( enter && !hp->items.more )
+ if ( !hp->items.more )
hashrehash( hp );
- if ( !enter && !hp->items.nel )
+ i = hash_search( hp, keyval, key, 0 );
+ if ( i )
{
- #ifdef HASH_DEBUG_PROFILE
- if ( DEBUG_PROFILE )
- profile_exit( prof );
- #endif
- return 0;
+ *found = 1;
}
-
- i = hash_search( hp, keyval, (*data)->key, 0 );
- if (i)
- {
- *data = &i->data;
- #ifdef HASH_DEBUG_PROFILE
- if ( DEBUG_PROFILE ) profile_exit( prof );
- #endif
- return !0;
- }
-
- if ( enter )
+ else
{
- ITEM * * base = hash_bucket(hp,keyval);
+ ITEM * * base = hash_bucket( hp, keyval );
/* try to grab one from the free list */
if ( hp->items.free )
{
i = hp->items.free;
hp->items.free = i->hdr.next;
- assert( i->data.key == 0 );
+ assert( hash_item_key( i ) == 0 );
}
else
{
@@ -261,24 +162,58 @@ hashitem(
hp->items.next += hp->items.size;
}
hp->items.more--;
- memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
- i->hdr.keyval = keyval;
i->hdr.next = *base;
*base = i;
- *data = &i->data;
- #ifdef OPT_BOEHM_GC
- if (sizeof(HASHDATA) == hp->items.datalen)
- {
- GC_REGISTER_FINALIZER(i->data.key,&hash_mem_finalizer,hp,0,0);
- }
+ *found = 0;
+ }
+
+ #ifdef HASH_DEBUG_PROFILE
+ if ( DEBUG_PROFILE )
+ profile_exit( prof );
+ #endif
+
+ 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 )
+{
+ ITEM *i;
+ unsigned int keyval = hash_keyval(key);
+
+ #ifdef HASH_DEBUG_PROFILE
+ profile_frame prof[1];
+ if ( DEBUG_PROFILE )
+ profile_enter( 0, prof );
+ #endif
+
+ if ( !hp->items.nel )
+ {
+ #ifdef HASH_DEBUG_PROFILE
+ if ( DEBUG_PROFILE )
+ profile_exit( prof );
#endif
+ return 0;
}
+ i = hash_search( hp, keyval, key, 0 );
+
#ifdef HASH_DEBUG_PROFILE
if ( DEBUG_PROFILE )
profile_exit( prof );
#endif
- return 0;
+
+ if (i)
+ {
+ return hash_item_data( i );
+ }
+ else
+ {
+ return 0;
+ }
}
/*
@@ -289,7 +224,7 @@ static void hashrehash( register struct hash *hp )
{
int i = ++hp->items.list;
hp->items.more = i ? 2 * hp->items.nel : hp->inel;
- hp->items.next = (char *)hash_mem_alloc( hp->items.datalen, hp->items.more * hp->items.size );
+ hp->items.next = (char *)BJAM_MALLOC( hp->items.more * hp->items.size );
hp->items.free = 0;
hp->items.lists[i].nel = hp->items.more;
@@ -297,10 +232,10 @@ static void hashrehash( register struct hash *hp )
hp->items.nel += hp->items.more;
if ( hp->tab.base )
- hash_mem_free( hp->items.datalen, (char *)hp->tab.base );
+ BJAM_FREE( (char *)hp->tab.base );
hp->tab.nel = hp->items.nel * hp->bloat;
- hp->tab.base = (ITEM **)hash_mem_alloc( hp->items.datalen, 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 * ) );
@@ -312,9 +247,9 @@ static void hashrehash( register struct hash *hp )
for ( ; nel--; next += hp->items.size )
{
register ITEM *i = (ITEM *)next;
- ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
+ 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( i->data.key != 0 );
+ assert( hash_item_key( i ) != 0 );
i->hdr.next = *ip;
*ip = i;
@@ -335,8 +270,8 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
for ( ; nel--; next += hp->items.size )
{
ITEM * i = (ITEM *)next;
- if ( i->data.key != 0 ) /* DO not enumerate freed items. */
- f( &i->data, data );
+ if ( hash_item_key( i ) != 0 ) /* DO not enumerate freed items. */
+ f( hash_item_data( i ), data );
}
}
}
@@ -352,16 +287,15 @@ void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data
struct hash *
hashinit(
int datalen,
- char *name )
+ const char *name )
{
- struct hash *hp = (struct hash *)hash_mem_alloc( datalen, sizeof( *hp ) );
+ 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.datalen = datalen;
hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
hp->items.list = -1;
hp->items.nel = 0;
@@ -371,89 +305,92 @@ hashinit(
return hp;
}
+void hashdone( struct hash * hp )
+{
+ if ( !hp )
+ return;
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ hashstat( hp );
+ hash_free( hp );
+}
+
/*
- * hashdone() - free a hash table, given its handle
+ * hash_free() - free a hash table, given its handle
*/
void
-hashdone( struct hash *hp )
+hash_free( struct hash * hp )
{
int i;
if ( !hp )
return;
- if ( DEBUG_MEM || DEBUG_PROFILE )
- hashstat( hp );
-
if ( hp->tab.base )
- hash_mem_free( hp->items.datalen, (char *)hp->tab.base );
+ BJAM_FREE( (char *)hp->tab.base );
for ( i = 0; i <= hp->items.list; ++i )
- hash_mem_free( hp->items.datalen, hp->items.lists[i].base );
- hash_mem_free( hp->items.datalen, (char *)hp );
+ BJAM_FREE( hp->items.lists[i].base );
+ BJAM_FREE( (char *)hp );
}
-static void * hash_mem_alloc(size_t datalen, size_t size)
-{
- if (sizeof(HASHDATA) == datalen)
- {
- return BJAM_MALLOC_RAW(size);
- }
- else
- {
- return BJAM_MALLOC(size);
- }
-}
-static void hash_mem_free(size_t datalen, void * data)
+/* ---- */
+
+static void hashstat( struct hash * hp )
{
- if (sizeof(HASHDATA) == datalen)
- {
- BJAM_FREE_RAW(data);
- }
- else
- {
- BJAM_FREE(data);
- }
+ struct hashstats stats[ 1 ];
+ hashstats_init( stats );
+ hashstats_add( stats, hp );
+ hashstats_print( stats, hp->name );
}
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(char * key, struct hash * hp)
+void hashstats_init( struct hashstats * stats )
{
- HASHDATA d;
- d.key = key;
- hash_free(hp,&d);
+ stats->count = 0;
+ stats->num_items = 0;
+ stats->tab_size = 0;
+ stats->item_size = 0;
+ stats->sets = 0;
}
-#endif
-
-/* ---- */
-
-static void hashstat( struct hash * hp )
+void hashstats_add( struct hashstats * stats, struct hash * hp )
{
- ITEM * * tab = hp->tab.base;
- int nel = hp->tab.nel;
- int count = 0;
- int sets = 0;
- int run = ( tab[ nel - 1 ] != (ITEM *)0 );
- int i;
- int here;
-
- for ( i = nel; i > 0; --i )
+ if ( hp )
{
- if ( ( here = ( *tab++ != (ITEM *)0 ) ) )
- count++;
- if ( here && !run )
- sets++;
- run = here;
+ ITEM * * tab = hp->tab.base;
+ int nel = hp->tab.nel;
+ int count = 0;
+ int sets = 0;
+ int i;
+
+ for ( i = 0; i < nel; ++i )
+ {
+ ITEM * item;
+ int here = 0;
+ for ( item = tab[ i ]; item != 0; item = item->hdr.next )
+ ++here;
+
+ count += here;
+ if ( here > 0 )
+ ++sets;
+ }
+
+ stats->count += count;
+ stats->sets += sets;
+ stats->num_items += hp->items.nel;
+ stats->tab_size += hp->tab.nel;
+ stats->item_size = hp->items.size;
}
+}
+void hashstats_print( struct hashstats * stats, const char * name )
+{
printf( "%s table: %d+%d+%d (%dK+%luK) items+table+hash, %f density\n",
- hp->name,
- count,
- hp->items.nel,
- hp->tab.nel,
- hp->items.nel * hp->items.size / 1024,
- (long unsigned)hp->tab.nel * sizeof( ITEM ** ) / 1024,
- (float)count / (float)sets );
+ name,
+ stats->count,
+ stats->num_items,
+ stats->tab_size,
+ stats->num_items * stats->item_size / 1024,
+ (long unsigned)stats->tab_size * sizeof( ITEM ** ) / 1024,
+ (float)stats->count / (float)stats->sets );
}
diff --git a/tools/build/v2/engine/hash.h b/tools/build/v2/engine/hash.h
index 7195b4146f..65db56c1c5 100644
--- a/tools/build/v2/engine/hash.h
+++ b/tools/build/v2/engine/hash.h
@@ -11,15 +11,68 @@
#ifndef BOOST_JAM_HASH_H
#define BOOST_JAM_HASH_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.
+ */
typedef struct hashdata HASHDATA;
-struct hash * hashinit ( int datalen, char * name );
-int hashitem ( struct hash * hp, HASHDATA * * data, int enter );
-void hashdone ( struct hash * hp );
+/*
+ * hashinit() - initialize a hash table, returning a handle.
+ * datalen is the size of the items. name is used for debugging.
+ */
+struct hash * hashinit ( int datalen, const char * name );
+
+/*
+ * hash_free() - free a hash table, given its handle
+ */
+void hash_free( struct hash * hp );
+void hashdone( struct hash * hp );
+
+/*
+ * hashenumerate() - call f(i, data) on each item, i in the hash
+ * table. The order of the items is unspecified.
+ */
void hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data );
-int hash_free ( struct hash * hp, HASHDATA * data);
-#define hashenter( hp, data ) ( !hashitem( hp, data, !0 ) )
-#define hashcheck( hp, data ) hashitem( hp, data, 0 )
+/*
+ * 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
+ *
+ * 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.
+ */
+HASHDATA * hash_insert ( struct hash * hp, 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 );
+
+struct hashstats {
+ int count;
+ int num_items;
+ int tab_size;
+ int item_size;
+ int sets;
+};
+
+void hashstats_init( struct hashstats * stats );
+void hashstats_add( struct hashstats * stats, struct hash * hp );
+void hashstats_print( struct hashstats * stats, const char * name );
#endif
diff --git a/tools/build/v2/engine/hcache.c b/tools/build/v2/engine/hcache.c
index 70bb798cc9..9e7a0343ed 100644
--- a/tools/build/v2/engine/hcache.c
+++ b/tools/build/v2/engine/hcache.c
@@ -8,11 +8,12 @@
# include "rules.h"
# include "regexp.h"
# include "headers.h"
-# include "newstr.h"
+# include "object.h"
# include "hash.h"
# include "hcache.h"
# include "variable.h"
# include "search.h"
+# include "modules.h"
#ifdef OPT_HEADER_CACHE_EXT
@@ -43,7 +44,7 @@ typedef struct hcachedata HCACHEDATA ;
struct hcachedata
{
- char * boundname;
+ OBJECT * boundname;
time_t time;
LIST * includes;
LIST * hdrscan; /* the HDRSCAN value for this target */
@@ -70,30 +71,30 @@ static int hits = 0;
* the result so the user can not change the cache file during header scanning.
*/
-static char * cache_name( void )
+static const char * cache_name( void )
{
- static char * name = 0;
+ static OBJECT * name = 0;
if ( !name )
{
- LIST * hcachevar = var_get( "HCACHEFILE" );
+ LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE );
- if ( hcachevar )
+ if ( !list_empty( hcachevar ) )
{
- TARGET * t = bindtarget( hcachevar->string );
+ TARGET * t = bindtarget( list_front( hcachevar ) );
- pushsettings( t->settings );
+ pushsettings( root_module(), t->settings );
/* Do not expect the cache file to be generated, so pass 0 as the
* third argument to search. Expect the location to be specified via
* LOCATE, so pass 0 as the fourth arugment.
*/
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, 0, 0 );
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
- if ( hcachevar )
- name = copystr( t->boundname );
+ name = object_copy( t->boundname );
}
}
- return name;
+ return name ? object_str( name ) : 0;
}
@@ -105,10 +106,10 @@ static char * cache_name( void )
static int cache_maxage( void )
{
int age = 100;
- LIST * var = var_get( "HCACHEMAXAGE" );
- if ( var )
+ LIST * var = var_get( root_module(), constant_HCACHEMAXAGE );
+ if ( !list_empty( var ) )
{
- age = atoi( var->string );
+ age = atoi( object_str( list_front( var ) ) );
if ( age < 0 )
age = 0;
}
@@ -118,10 +119,10 @@ static int cache_maxage( void )
/*
* Read a netstring. The caveat is that the string can not contain ASCII 0. The
- * returned value is as returned by newstr(), so it need not be freed.
+ * returned value is as returned by object_new().
*/
-char * read_netstring( FILE * f )
+OBJECT * read_netstring( FILE * f )
{
unsigned long len;
static char * buf = NULL;
@@ -154,7 +155,7 @@ char * read_netstring( FILE * f )
return NULL;
buf[ len ] = 0;
- return newstr( buf );
+ return object_new( buf );
}
@@ -172,12 +173,13 @@ void write_netstring( FILE * f, char const * s )
void hcache_init()
{
- HCACHEDATA cachedata;
- HCACHEDATA * c;
FILE * f;
- char * version;
+ OBJECT * version = 0;
int header_count = 0;
- char * hcachename;
+ const char * hcachename;
+
+ if ( hcachehash )
+ return;
hcachehash = hashinit( sizeof( HCACHEDATA ), "hcache" );
@@ -188,105 +190,144 @@ void hcache_init()
return;
version = read_netstring( f );
- if ( !version || strcmp( version, CACHE_FILE_VERSION ) )
- {
- fclose( f );
- return;
- }
+
+ if ( !version || strcmp( object_str( version ), CACHE_FILE_VERSION ) )
+ goto bail;
while ( 1 )
{
- char * record_type;
- char * time_str;
- char * age_str;
- char * includes_count_str;
- char * hdrscan_count_str;
- int i;
- int count;
- LIST * l;
+ HCACHEDATA cachedata;
+ HCACHEDATA * c;
+ OBJECT * record_type = 0;
+ OBJECT * time_str = 0;
+ OBJECT * age_str = 0;
+ OBJECT * includes_count_str = 0;
+ OBJECT * hdrscan_count_str = 0;
+ int i;
+ int count;
+ LIST * l;
+ int found;
+
+ cachedata.boundname = 0;
+ cachedata.includes = 0;
+ cachedata.hdrscan = 0;
record_type = read_netstring( f );
if ( !record_type )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- if ( !strcmp( record_type, CACHE_RECORD_END ) )
+ if ( !strcmp( object_str( record_type ), CACHE_RECORD_END ) )
+ {
+ object_free( record_type );
break;
- if ( strcmp( record_type, CACHE_RECORD_HEADER ) )
+ }
+ if ( strcmp( object_str( record_type ), CACHE_RECORD_HEADER ) )
{
fprintf( stderr, "invalid %s with record separator <%s>\n",
- hcachename, record_type ? record_type : "<null>" );
- goto bail;
+ hcachename, record_type ? object_str( record_type ) : "<null>" );
+ goto cleanup;
}
- c = &cachedata;
-
- c->boundname = read_netstring( f );
- time_str = read_netstring( f );
- age_str = read_netstring( f );
- includes_count_str = read_netstring( f );
+ cachedata.boundname = read_netstring( f );
+ time_str = read_netstring( f );
+ age_str = read_netstring( f );
+ includes_count_str = read_netstring( f );
- if ( !c->boundname || !time_str || !age_str || !includes_count_str )
+ if ( !cachedata.boundname || !time_str || !age_str || !includes_count_str )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- c->time = atoi( time_str );
- c->age = atoi( age_str ) + 1;
+ cachedata.time = atoi( object_str( time_str ) );
+ cachedata.age = atoi( object_str( age_str ) ) + 1;
- count = atoi( includes_count_str );
- for ( l = 0, i = 0; i < count; ++i )
+ count = atoi( object_str( includes_count_str ) );
+ for ( l = L0, i = 0; i < count; ++i )
{
- char * s = read_netstring( f );
+ OBJECT * s = read_netstring( f );
if ( !s )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ list_free( l );
+ goto cleanup;
}
- l = list_new( l, s );
+ l = list_push_back( l, s );
}
- c->includes = l;
+ cachedata.includes = l;
hdrscan_count_str = read_netstring( f );
- if ( !includes_count_str )
+ if ( !hdrscan_count_str )
{
- list_free( c->includes );
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ goto cleanup;
}
- count = atoi( hdrscan_count_str );
- for ( l = 0, i = 0; i < count; ++i )
+ count = atoi( object_str( hdrscan_count_str ) );
+ for ( l = L0, i = 0; i < count; ++i )
{
- char * s = read_netstring( f );
+ OBJECT * s = read_netstring( f );
if ( !s )
{
fprintf( stderr, "invalid %s\n", hcachename );
- goto bail;
+ list_free( l );
+ goto cleanup;
}
- l = list_new( l, s );
+ l = list_push_back( l, s );
}
- c->hdrscan = l;
+ cachedata.hdrscan = l;
- if ( !hashenter( hcachehash, (HASHDATA * *)&c ) )
+ 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;
+ }
+ else
{
fprintf( stderr, "can't insert header cache item, bailing on %s\n",
hcachename );
- goto bail;
+ goto cleanup;
}
c->next = hcachelist;
hcachelist = c;
++header_count;
+
+ object_free( record_type );
+ object_free( time_str );
+ object_free( age_str );
+ object_free( includes_count_str );
+ object_free( hdrscan_count_str );
+ continue;
+
+cleanup:
+
+ if ( record_type ) object_free( record_type );
+ if ( time_str ) object_free( time_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 );
+
+ if ( cachedata.boundname ) object_free( cachedata.boundname );
+ if ( cachedata.includes ) list_free( cachedata.includes );
+ if ( cachedata.hdrscan ) list_free( cachedata.hdrscan );
+
+ goto bail;
}
if ( DEBUG_HEADER )
printf( "hcache read from file %s\n", hcachename );
- bail:
+bail:
+ if ( version )
+ object_free( version );
fclose( f );
}
@@ -296,17 +337,17 @@ void hcache_done()
FILE * f;
HCACHEDATA * c;
int header_count = 0;
- char * hcachename;
+ const char * hcachename;
int maxage;
if ( !hcachehash )
return;
if ( !( hcachename = cache_name() ) )
- return;
+ goto cleanup;
if ( !( f = fopen( hcachename, "wb" ) ) )
- return;
+ goto cleanup;
maxage = cache_maxage();
@@ -316,7 +357,7 @@ void hcache_done()
c = hcachelist;
for ( c = hcachelist; c; c = c->next )
{
- LIST * l;
+ LISTITER iter, end;
char time_str[ 30 ];
char age_str[ 30 ];
char includes_count_str[ 30 ];
@@ -333,15 +374,17 @@ void hcache_done()
sprintf( age_str, "%lu", (long unsigned) c->age );
write_netstring( f, CACHE_RECORD_HEADER );
- write_netstring( f, c->boundname );
+ write_netstring( f, object_str( c->boundname ) );
write_netstring( f, time_str );
write_netstring( f, age_str );
write_netstring( f, includes_count_str );
- for ( l = c->includes; l; l = list_next( l ) )
- write_netstring( f, l->string );
+ for ( iter = list_begin( c->includes ), end = list_end( c->includes );
+ iter != end; iter = list_next( iter ) )
+ write_netstring( f, object_str( list_item( iter ) ) );
write_netstring( f, hdrscan_count_str );
- for ( l = c->hdrscan; l; l = list_next( l ) )
- write_netstring( f, l->string );
+ for ( iter = list_begin( c->hdrscan ), end = list_end( c->hdrscan );
+ iter != end; iter = list_next( iter ) )
+ write_netstring( f, object_str( list_item( iter ) ) );
fputs( "\n", f );
++header_count;
}
@@ -352,81 +395,110 @@ void hcache_done()
hcachename, header_count, queries ? 100.0 * hits / queries : 0 );
fclose ( f );
+
+cleanup:
+ for ( c = hcachelist; c; c = c->next )
+ {
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ object_free( c->boundname );
+ }
+
+ hcachelist = 0;
+ if ( hcachehash )
+ hashdone( hcachehash );
+ hcachehash = 0;
}
LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
{
- HCACHEDATA cachedata;
- HCACHEDATA * c = &cachedata;
+ HCACHEDATA * c;
LIST * l = 0;
++queries;
- c->boundname = t->boundname;
-
- if (hashcheck (hcachehash, (HASHDATA **) &c))
- {
- if (c->time == t->time)
+ if ( ( c = (HCACHEDATA *)hash_find( hcachehash, t->boundname ) ) )
{
- LIST *l1 = hdrscan, *l2 = c->hdrscan;
- while (l1 && l2) {
- if (l1->string != l2->string) {
- l1 = NULL;
- } else {
- l1 = list_next(l1);
- l2 = list_next(l2);
- }
+ if ( 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 );
+ while ( iter1 != end1 && iter2 != end2 )
+ {
+ if ( !object_equal( list_item( iter1 ), list_item( iter2 ) ) )
+ {
+ iter1 = end1;
+ }
+ else
+ {
+ iter1 = list_next( iter1 );
+ iter2 = list_next( iter2 );
+ }
+ }
+ if ( iter1 != end1 || iter2 != end2 )
+ {
+ 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" );
+
+ list_free( c->includes );
+ list_free( c->hdrscan );
+ c->includes = L0;
+ c->hdrscan = L0;
+ }
+ else
+ {
+ 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;
+ }
}
- if (l1 || l2) {
- if (DEBUG_HEADER)
- printf("HDRSCAN out of date in cache for %s\n",
- t->boundname);
-
- printf("HDRSCAN out of date for %s\n", t->boundname);
- printf(" real : ");
- list_print(hdrscan);
- printf("\n cached: ");
- list_print(c->hdrscan);
- printf("\n");
-
- list_free(c->includes);
- list_free(c->hdrscan);
- c->includes = 0;
- c->hdrscan = 0;
- } else {
- if (DEBUG_HEADER)
- printf ("using header cache for %s\n", t->boundname);
- c->age = 0;
- ++hits;
- l = list_copy (0, c->includes);
- return l;
+ else
+ {
+ 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;
+ c->hdrscan = L0;
}
- } else {
- if (DEBUG_HEADER)
- printf ("header cache out of date for %s\n", t->boundname);
- list_free (c->includes);
- list_free(c->hdrscan);
- c->includes = 0;
- c->hdrscan = 0;
- }
- } else {
- if (hashenter (hcachehash, (HASHDATA **)&c)) {
- c->boundname = newstr (c->boundname);
- c->next = hcachelist;
- hcachelist = c;
}
+ else
+ {
+ int found;
+ c = (HCACHEDATA *)hash_insert( hcachehash, t->boundname, &found );
+ if ( !found )
+ {
+ c->boundname = object_copy( t->boundname );
+ c->next = hcachelist;
+ hcachelist = c;
+ }
}
/* 'c' points at the cache entry. Its out of date. */
- l = headers1 (0, t->boundname, rec, re);
+ l = headers1( L0, t->boundname, rec, re );
c->time = t->time;
c->age = 0;
- c->includes = list_copy (0, l);
- c->hdrscan = list_copy(0, hdrscan);
+ c->includes = list_copy( l );
+ c->hdrscan = list_copy( hdrscan );
return l;
}
diff --git a/tools/build/v2/engine/hcache.h b/tools/build/v2/engine/hcache.h
index c316e3bcad..2aa2394939 100644
--- a/tools/build/v2/engine/hcache.h
+++ b/tools/build/v2/engine/hcache.h
@@ -11,8 +11,8 @@
# include "regexp.h"
# include "lists.h"
-void hcache_init(void);
-void hcache_done(void);
-LIST *hcache(TARGET *t, int rec, regexp *re[], LIST *hdrscan);
+void hcache_init( void );
+void hcache_done( void );
+LIST * hcache( TARGET *t, int rec, regexp * re[], LIST * hdrscan );
#endif
diff --git a/tools/build/v2/engine/hdrmacro.c b/tools/build/v2/engine/hdrmacro.c
index 43031d48ff..6ef2a131c9 100644
--- a/tools/build/v2/engine/hdrmacro.c
+++ b/tools/build/v2/engine/hdrmacro.c
@@ -19,7 +19,7 @@
# include "regexp.h"
# include "hdrmacro.h"
# include "hash.h"
-# include "newstr.h"
+# include "object.h"
# include "strings.h"
/*
@@ -49,8 +49,8 @@
/* this type is used to store a dictionary of file header macros */
typedef struct header_macro
{
- char * symbol;
- char * filename; /* we could maybe use a LIST here ?? */
+ OBJECT * symbol;
+ OBJECT * filename; /* we could maybe use a LIST here ?? */
} HEADER_MACRO;
static struct hash * header_macros_hash = 0;
@@ -63,26 +63,28 @@ static struct hash * header_macros_hash = 0;
# define MAXINC 10
void
-macro_headers( TARGET *t )
+macro_headers( TARGET * t )
{
static regexp *re = 0;
FILE *f;
char buf[ 1024 ];
if ( DEBUG_HEADER )
- printf( "macro header scan for %s\n", t->name );
+ 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 )
{
- re = regex_compile(
+ OBJECT * re_str = object_new(
"^[ ]*#[ ]*define[ ]*([A-Za-z][A-Za-z0-9_]*)[ ]*"
"[<\"]([^\">]*)[\">].*$" );
+ re = regex_compile( re_str );
+ object_free( re_str );
}
- if ( !( f = fopen( t->boundname, "r" ) ) )
+ if ( !( f = fopen( object_str( t->boundname ), "r" ) ) )
return;
while ( fgets( buf, sizeof( buf ), f ) )
@@ -92,24 +94,30 @@ macro_headers( TARGET *t )
if ( regexec( re, buf ) && re->startp[1] )
{
+ OBJECT * symbol;
+ int found;
/* we detected a line that looks like "#define MACRO filename */
- re->endp[1][0] = '\0';
- 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], 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" );
- v->symbol = re->startp[1];
- v->filename = 0;
- if ( hashenter( header_macros_hash, (HASHDATA **)&v ) )
+ symbol = object_new( re->startp[1] );
+ v = (HEADER_MACRO *)hash_insert( header_macros_hash, symbol, &found );
+ if ( !found )
{
- v->symbol = newstr( re->startp[1] ); /* never freed */
- v->filename = newstr( re->startp[2] ); /* never freed */
+ v->symbol = symbol;
+ 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.. */
@@ -120,17 +128,14 @@ macro_headers( TARGET *t )
}
-char * macro_header_get( const char * macro_name )
+OBJECT * macro_header_get( OBJECT * macro_name )
{
- HEADER_MACRO var;
- HEADER_MACRO * v = &var;
-
- v->symbol = (char* )macro_name;
+ HEADER_MACRO * v;
- if ( header_macros_hash && hashcheck( header_macros_hash, (HASHDATA **)&v ) )
+ if ( header_macros_hash && ( v = (HEADER_MACRO *)hash_find( header_macros_hash, macro_name ) ) )
{
if ( DEBUG_HEADER )
- printf( "### macro '%s' evaluated to '%s'\n", macro_name, v->filename );
+ printf( "### macro '%s' evaluated to '%s'\n", object_str( macro_name ), object_str( v->filename ) );
return v->filename;
}
return 0;
diff --git a/tools/build/v2/engine/hdrmacro.h b/tools/build/v2/engine/hdrmacro.h
index 08cc111600..ddfa6eeac2 100644
--- a/tools/build/v2/engine/hdrmacro.h
+++ b/tools/build/v2/engine/hdrmacro.h
@@ -9,6 +9,11 @@
* #define MACRO "filename" definitions
*/
+#ifndef HDRMACRO_SW20111118_H
+#define HDRMACRO_SW20111118_H
+
void macro_headers( TARGET *t );
-char* macro_header_get( const char* macro_name );
+OBJECT * macro_header_get( OBJECT * macro_name );
+
+#endif
diff --git a/tools/build/v2/engine/headers.c b/tools/build/v2/engine/headers.c
index b9d8f6370d..7e01440169 100644
--- a/tools/build/v2/engine/headers.c
+++ b/tools/build/v2/engine/headers.c
@@ -14,11 +14,12 @@
# 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 "newstr.h"
+# include "object.h"
#ifdef OPT_HEADER_CACHE_EXT
# include "hcache.h"
@@ -46,7 +47,7 @@
*/
#ifndef OPT_HEADER_CACHE_EXT
-static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]);
+static LIST * headers1( LIST * l, OBJECT * file, int rec, regexp * re[]);
#endif
/*
@@ -56,28 +57,33 @@ static LIST *headers1( LIST *l, char *file, int rec, regexp *re[]);
# define MAXINC 10
void
-headers( TARGET *t )
+headers( TARGET * t )
{
LIST * hdrscan;
LIST * hdrrule;
#ifndef OPT_HEADER_CACHE_EXT
- LIST * headlist = 0;
+ LIST * headlist = L0;
#endif
regexp * re[ MAXINC ];
int rec = 0;
+ LISTITER iter, end;
- if ( !( hdrscan = var_get( "HDRSCAN" ) ) ||
- !( hdrrule = var_get( "HDRRULE" ) ) )
+ hdrscan = var_get( root_module(), constant_HDRSCAN );
+ if ( list_empty( hdrscan ) )
+ return;
+
+ hdrrule = var_get( root_module(), constant_HDRRULE );
+ if ( list_empty( hdrrule ) )
return;
if ( DEBUG_HEADER )
- printf( "header scan %s\n", t->name );
+ printf( "header scan %s\n", object_str( t->name ) );
/* Compile all regular expressions in HDRSCAN */
- while ( ( rec < MAXINC ) && hdrscan )
+ iter = list_begin( hdrscan ), end = list_end( hdrscan );
+ for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) )
{
- re[ rec++ ] = regex_compile( hdrscan->string );
- hdrscan = list_next( hdrscan );
+ re[ rec++ ] = regex_compile( list_item( iter ) );
}
/* Doctor up call to HDRRULE rule */
@@ -85,7 +91,7 @@ headers( TARGET *t )
{
FRAME frame[1];
frame_init( frame );
- lol_add( frame->args, list_new( L0, t->name ) );
+ lol_add( frame->args, list_new( object_copy( t->name ) ) );
#ifdef OPT_HEADER_CACHE_EXT
lol_add( frame->args, hcache( t, rec, re, hdrscan ) );
#else
@@ -96,9 +102,9 @@ headers( TARGET *t )
{
/* The third argument to HDRRULE is the bound name of
* $(<) */
- lol_add( frame->args, list_new( L0, t->boundname ) );
+ lol_add( frame->args, list_new( object_copy( t->boundname ) ) );
- list_free( evaluate_rule( hdrrule->string, frame ) );
+ list_free( evaluate_rule( list_front( hdrrule ), frame ) );
}
/* Clean up. */
@@ -118,7 +124,7 @@ static LIST *
#endif
headers1(
LIST * l,
- char * file,
+ OBJECT * file,
int rec,
regexp * re[] )
{
@@ -137,10 +143,14 @@ headers1(
/* the following regexp is used to detect cases where a */
/* file is included through a line line "#include MACRO" */
if ( re_macros == 0 )
- re_macros = regex_compile(
+ {
+ OBJECT * re_str = object_new(
"^[ ]*#[ ]*include[ ]*([A-Za-z][A-Za-z0-9_]*).*$" );
+ re_macros = regex_compile( re_str );
+ object_free( re_str );
+ }
- if ( !( f = fopen( file, "r" ) ) )
+ if ( !( f = fopen( object_str( file ), "r" ) ) )
return l;
while ( fgets( buf, sizeof( buf ), f ) )
@@ -158,30 +168,33 @@ headers1(
for ( i = 0; i < rec; ++i )
if ( regexec( re[i], buf ) && re[i]->startp[1] )
{
- 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_new( l, newstr( 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] )
{
- char* header_filename;
+ OBJECT * header_filename;
+ OBJECT * macro_name;
- 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] );
- header_filename = macro_header_get( 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", header_filename );
- l = list_new( l, newstr( header_filename ) );
+ printf( " resolved to '%s'\n", object_str( header_filename ) );
+ l = list_push_back( l, object_copy( header_filename ) );
}
else
{
@@ -197,7 +210,7 @@ headers1(
}
-void regerror( char * s )
+void regerror( const char * s )
{
printf( "re error %s\n", s );
}
diff --git a/tools/build/v2/engine/headers.h b/tools/build/v2/engine/headers.h
index 624475fe7d..1c0a642df8 100644
--- a/tools/build/v2/engine/headers.h
+++ b/tools/build/v2/engine/headers.h
@@ -8,9 +8,18 @@
* headers.h - handle #includes in source files
*/
-void headers( TARGET *t );
+#ifndef HEADERS_SW20111118_H
+#define HEADERS_SW20111118_H
+
+#include "object.h"
+#include "rules.h"
+#include "regexp.h"
+
+void headers( TARGET * t );
#ifdef OPT_HEADER_CACHE_EXT
struct regexp;
-LIST *headers1( LIST *l, char *file, int rec, struct regexp *re[] );
+LIST * headers1( LIST *l, OBJECT * file, int rec, struct regexp *re[] );
+#endif
+
#endif
diff --git a/tools/build/v2/engine/jam.c b/tools/build/v2/engine/jam.c
index e11d082bca..09faf85225 100644
--- a/tools/build/v2/engine/jam.c
+++ b/tools/build/v2/engine/jam.c
@@ -54,18 +54,18 @@
* are layered thus:
*
* variable|expand
- * / | | |
- * / | | |
- * / | | |
- * lists | | pathsys
- * \ | |
- * \ | |
- * \ | |
- * newstr |
+ * / | |
+ * / | |
+ * / | |
+ * lists | pathsys
+ * \ |
+ * \ hash
+ * \ |
+ * \ |
* \ |
* \ |
* \ |
- * hash
+ * object
*
* Roughly, the modules are:
*
@@ -73,8 +73,6 @@
* command.c - maintain lists of commands
* compile.c - compile parsed jam statements
* execunix.c - execute a shell script on UNIX
- * execvms.c - execute a shell script, ala VMS
- * expand.c - expand a buffer, given variable values
* file*.c - scan directories and archives on *
* hash.c - simple in-memory hashing routines
* hdrmacro.c - handle header file parsing for filename macro definitions
@@ -84,7 +82,7 @@
* lists.c - maintain lists of strings
* make.c - bring a target up to date, once rules are in place
* make1.c - execute command to bring targets up to date
- * newstr.c - string manipulation routines
+ * 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 *
@@ -115,14 +113,20 @@
#include "compile.h"
#include "builtins.h"
#include "rules.h"
-#include "newstr.h"
+#include "object.h"
#include "scan.h"
#include "timestamp.h"
#include "make.h"
#include "strings.h"
-#include "expand.h"
#include "filesys.h"
#include "output.h"
+#include "search.h"
+#include "class.h"
+#include "execcmd.h"
+#include "constants.h"
+#include "function.h"
+#include "pwd.h"
+#include "hcache.h"
/* Macintosh is "special" */
#ifdef OS_MAC
@@ -196,7 +200,6 @@ static void run_unit_tests()
execnt_unit_test();
#endif
string_unit_test();
- var_expand_unit_test();
}
#endif
@@ -211,7 +214,9 @@ int anyhow = 0;
extern PyObject * bjam_caller ( PyObject * self, PyObject * args );
#endif
-char *saved_argv0;
+void regex_done();
+
+const char *saved_argv0;
int main( int argc, char * * argv, char * * arg_environ )
{
@@ -223,6 +228,7 @@ int main( int argc, char * * argv, char * * arg_environ )
int arg_c = argc;
char * * arg_v = argv;
char const * progname = argv[0];
+ module_t * environ_module;
saved_argv0 = argv[0];
@@ -338,6 +344,8 @@ int main( int argc, char * * argv, char * * arg_environ )
globs.debug[i--] = 1;
}
+ constants_init();
+
{
PROFILE_ENTER( MAIN );
@@ -377,14 +385,14 @@ int main( int argc, char * * argv, char * * arg_environ )
#endif
/* Set JAMDATE. */
- var_set( "JAMDATE", list_new( L0, outf_time(time(0)) ), VAR_SET );
+ var_set( root_module(), constant_JAMDATE, list_new( outf_time(time(0)) ), VAR_SET );
/* Set JAM_VERSION. */
- var_set( "JAM_VERSION",
- list_new( list_new( list_new( L0,
- newstr( VERSION_MAJOR_SYM ) ),
- newstr( VERSION_MINOR_SYM ) ),
- newstr( VERSION_PATCH_SYM ) ),
+ var_set( root_module(), constant_JAM_VERSION,
+ list_push_back( list_push_back( list_new(
+ object_new( VERSION_MAJOR_SYM ) ),
+ object_new( VERSION_MINOR_SYM ) ),
+ object_new( VERSION_PATCH_SYM ) ),
VAR_SET );
/* Set JAMUNAME. */
@@ -394,17 +402,17 @@ int main( int argc, char * * argv, char * * arg_environ )
if ( uname( &u ) >= 0 )
{
- var_set( "JAMUNAME",
- list_new(
- list_new(
- list_new(
- list_new(
- list_new( L0,
- newstr( u.sysname ) ),
- newstr( u.nodename ) ),
- newstr( u.release ) ),
- newstr( u.version ) ),
- newstr( u.machine ) ), VAR_SET );
+ var_set( root_module(), constant_JAMUNAME,
+ list_push_back(
+ list_push_back(
+ list_push_back(
+ list_push_back(
+ list_new(
+ object_new( u.sysname ) ),
+ object_new( u.nodename ) ),
+ object_new( u.release ) ),
+ object_new( u.version ) ),
+ object_new( u.machine ) ), VAR_SET );
}
}
#endif /* unix */
@@ -414,19 +422,18 @@ int main( int argc, char * * argv, char * * arg_environ )
/* First into the global module, with splitting, for backward
* compatibility.
*/
- var_defines( use_environ, 1 );
+ var_defines( root_module(), use_environ, 1 );
+ environ_module = bindmodule( constant_ENVIRON );
/* Then into .ENVIRON, without splitting. */
- enter_module( bindmodule(".ENVIRON") );
- var_defines( use_environ, 0 );
- exit_module( bindmodule(".ENVIRON") );
+ var_defines( environ_module, use_environ, 0 );
/*
* Jam defined variables OS & OSPLAT. We load them after environment, so
* that setting OS in environment does not change Jam's notion of the
* current platform.
*/
- var_defines( othersyms, 1 );
+ var_defines( root_module(), othersyms, 1 );
/* Load up variables set on command line. */
for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n )
@@ -434,16 +441,16 @@ int main( int argc, char * * argv, char * * arg_environ )
char *symv[2];
symv[ 0 ] = s;
symv[ 1 ] = 0;
- var_defines( symv, 1 );
- enter_module( bindmodule(".ENVIRON") );
- var_defines( symv, 0 );
- exit_module( bindmodule(".ENVIRON") );
+ var_defines( root_module(), symv, 1 );
+ var_defines( environ_module, symv, 0 );
}
/* Set the ARGV to reflect the complete list of arguments of invocation.
*/
for ( n = 0; n < arg_c; ++n )
- var_set( "ARGV", list_new( L0, newstr( 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();
@@ -459,29 +466,43 @@ int main( int argc, char * * argv, char * * arg_environ )
}
else
{
- mark_target_for_updating( arg_v[ n ] );
+ OBJECT * target = object_new( arg_v[ n ] );
+ mark_target_for_updating( target );
+ object_free( target );
}
}
- if (!targets_to_update())
- mark_target_for_updating("all");
+ if ( list_empty( targets_to_update() ) )
+ {
+ mark_target_for_updating( constant_all );
+ }
/* Parse ruleset. */
{
FRAME frame[ 1 ];
frame_init( frame );
for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n )
- parse_file( s, frame );
+ {
+ OBJECT * filename = object_new( s );
+ parse_file( filename, frame );
+ object_free( filename );
+ }
if ( !n )
- parse_file( "+", frame );
+ {
+ parse_file( constant_plus, frame );
+ }
}
status = yyanyerrors();
/* Manually touch -t targets. */
for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n )
- touch_target( s );
+ {
+ OBJECT * target = object_new( s );
+ touch_target( target );
+ object_free( target );
+ }
/* If an output file is specified, set globs.cmdout to that. */
if ( ( s = getoptval( optv, 'o', 0 ) ) )
@@ -498,13 +519,13 @@ int main( int argc, char * * argv, char * * arg_environ )
options. */
{
LIST *p = L0;
- p = var_get ("PARALLELISM");
- if (p)
+ p = var_get ( root_module(), constant_PARALLELISM );
+ if ( !list_empty( p ) )
{
- int j = atoi (p->string);
- if (j == -1)
+ int j = atoi( object_str( list_front( p ) ) );
+ if ( j == -1 )
{
- printf( "Invalid value of PARALLELISM: %s\n", p->string);
+ printf( "Invalid value of PARALLELISM: %s\n", object_str( list_front( p ) ) );
}
else
{
@@ -516,11 +537,11 @@ int main( int argc, char * * argv, char * * arg_environ )
/* KEEP_GOING overrides -q option. */
{
LIST *p = L0;
- p = var_get ("KEEP_GOING");
- if (p)
+ p = var_get( root_module(), constant_KEEP_GOING );
+ if ( !list_empty( p ) )
{
- int v = atoi (p->string);
- if (v == 0)
+ int v = atoi( object_str( list_front( p ) ) );
+ if ( v == 0 )
globs.quitquick = 1;
else
globs.quitquick = 0;
@@ -532,16 +553,9 @@ int main( int argc, char * * argv, char * * arg_environ )
PROFILE_ENTER( MAIN_MAKE );
LIST * targets = targets_to_update();
- if (targets)
+ if ( !list_empty( targets ) )
{
- int targets_count = list_length( targets );
- const char * * targets2 = (const char * *)
- BJAM_MALLOC( targets_count * sizeof( char * ) );
- int n = 0;
- for ( ; targets; targets = list_next( targets ) )
- targets2[ n++ ] = targets->string;
- status |= make( targets_count, targets2, anyhow );
- free( targets );
+ status |= make( targets, anyhow );
}
else
{
@@ -557,12 +571,28 @@ int main( int argc, char * * argv, char * * arg_environ )
if ( DEBUG_PROFILE )
profile_dump();
+
+#ifdef OPT_HEADER_CACHE_EXT
+ hcache_done();
+#endif
+
+ clear_targets_to_update();
+
/* Widely scattered cleanup. */
- var_done();
file_done();
rules_done();
stamps_done();
- str_done();
+ search_done();
+ class_done();
+ modules_done();
+ regex_done();
+ exec_done();
+ pwd_done();
+ path_done();
+ function_done();
+ list_done();
+ constants_done();
+ object_done();
/* Close cmdout. */
if ( globs.cmdout )
@@ -579,7 +609,7 @@ int main( int argc, char * * argv, char * * arg_environ )
#if defined(_WIN32)
#include <windows.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf));
if (ret == 0 || ret == sizeof(buf)) return NULL;
@@ -587,7 +617,7 @@ char *executable_path(char *argv0) {
}
#elif defined(__APPLE__) /* Not tested */
#include <mach-o/dyld.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
char buf[1024];
uint32_t size = sizeof(buf);
int ret = _NSGetExecutablePath(buf, &size);
@@ -597,12 +627,12 @@ char *executable_path(char *argv0) {
#elif defined(sun) || defined(__sun) /* Not tested */
#include <stdlib.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
return strdup(getexecname());
}
#elif defined(__FreeBSD__)
#include <sys/sysctl.h>
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
@@ -616,16 +646,16 @@ char *executable_path(char *argv0) {
}
#elif defined(__linux__)
#include <unistd.h>
-char *executable_path(char *argv0) {
+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);
}
#else
-char *executable_path(char *argv0) {
+char *executable_path(const char *argv0) {
/* If argv0 is absolute path, assume it's the right absolute path. */
- if (argv0[0] == "/")
+ if (argv0[0] == '/')
return strdup(argv0);
return NULL;
}
diff --git a/tools/build/v2/engine/jam.h b/tools/build/v2/engine/jam.h
index 73a7a04c58..26b94a7f7e 100644
--- a/tools/build/v2/engine/jam.h
+++ b/tools/build/v2/engine/jam.h
@@ -46,40 +46,6 @@
#define HAVE_POPEN 1
/*
- * VMS, OPENVMS
- */
-
-#ifdef VMS
-
-#include <types.h>
-#include <file.h>
-#include <stat.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <unixlib.h>
-
-#define OSMINOR "OS=VMS"
-#define OSMAJOR "VMS=true"
-#define OS_VMS
-#define MAXLINE 1024 /* longest 'together' actions */
-#define SPLITPATH ','
-#define EXITOK 1
-#define EXITBAD 0
-#define DOWNSHIFT_PATHS
-
-/* This may be inaccurate. */
-#ifndef __DECC
-#define OSPLAT "OSPLAT=VAX"
-#endif
-
-#endif
-
-/*
* Windows NT
*/
@@ -157,55 +123,6 @@
#endif
/*
- * OS2
- */
-
-#ifdef __OS2__
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <malloc.h>
-#include <signal.h>
-#include <string.h>
-#include <time.h>
-
-#define OSMAJOR "OS2=true"
-#define OSMINOR "OS=OS2"
-#define OS_OS2
-#define SPLITPATH ';'
-#define MAXLINE 996 /* longest 'together' actions */
-#define USE_EXECUNIX
-#define USE_PATHUNIX
-#define PATH_DELIM '\\'
-#define DOWNSHIFT_PATHS
-
-#ifdef __EMX__
- #define USE_FILEUNIX
-#endif
-
-#endif
-
-/*
- * Macintosh MPW
- */
-
-#ifdef macintosh
-
-#include <time.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#define OSMAJOR "MAC=true"
-#define OSMINOR "OS=MAC"
-#define OS_MAC
-#define SPLITPATH ','
-
-#endif
-
-/*
* God fearing UNIX.
*/
diff --git a/tools/build/v2/engine/jamgram.c b/tools/build/v2/engine/jamgram.c
index b1fa0835df..48c85228e8 100644
--- a/tools/build/v2/engine/jamgram.c
+++ b/tools/build/v2/engine/jamgram.c
@@ -1,30 +1,38 @@
-/* A Bison parser, made by GNU Bison 1.875. */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
+/* A Bison parser, made by GNU Bison 2.4.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* Written by Richard Stallman by simplifying the original so called
- ``semantic'' parser. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
/* All symbols defined below should begin with yy or YY, to avoid
infringing on user name space. This should be done even for local
@@ -36,17 +44,93 @@
/* Identify Bison output. */
#define YYBISON 1
+/* Bison version. */
+#define YYBISON_VERSION "2.4.3"
+
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
/* Pure parsers. */
#define YYPURE 0
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
/* Using locations. */
#define YYLSP_NEEDED 0
+/* Copy the first part of user declarations. */
+
+/* Line 189 of yacc.c */
+#line 96 "jamgram.y"
+
+#include "jam.h"
+
+#include "lists.h"
+#include "parse.h"
+#include "scan.h"
+#include "compile.h"
+#include "object.h"
+#include "rules.h"
+
+# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
+
+# define F0 -1
+# define P0 (PARSE *)0
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
+
+# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
+# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+
+
+
+/* Line 189 of yacc.c */
+#line 114 "y.tab.c"
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -101,6 +185,7 @@
STRING = 303
};
#endif
+/* Tokens. */
#define _BANG_t 258
#define _BANG_EQUALS_t 259
#define _AMPER_t 260
@@ -151,119 +236,184 @@
-/* Copy the first part of user declarations. */
-#line 96 "jamgram.y"
-
-#include "jam.h"
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
-#include "lists.h"
-#include "parse.h"
-#include "scan.h"
-#include "compile.h"
-#include "newstr.h"
-#include "rules.h"
-# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
+/* Copy the second part of user declarations. */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
-# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
-# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
-# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
+/* Line 264 of yacc.c */
+#line 252 "y.tab.c"
+#ifdef short
+# undef short
+#endif
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
#endif
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
#else
-# define YYERROR_VERBOSE 0
+typedef unsigned short int yytype_uint16;
#endif
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
#endif
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-/* Copy the second part of user declarations. */
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
-/* Line 214 of yacc.c. */
-#line 223 "y.tab.c"
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
-#if ! defined (yyoverflow) || YYERROR_VERBOSE
+#if ! defined yyoverflow || YYERROR_VERBOSE
/* The parser invokes alloca or malloc; define the necessary symbols. */
-# if YYSTACK_USE_ALLOCA
-# define YYSTACK_ALLOC alloca
-# else
-# ifndef YYSTACK_USE_ALLOCA
-# if defined (alloca) || defined (_ALLOCA_H)
-# define YYSTACK_ALLOC alloca
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
# else
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
# endif
# endif
# endif
# endif
# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
# else
-# if defined (__STDC__) || defined (__cplusplus)
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
# endif
-# define YYSTACK_ALLOC malloc
-# define YYSTACK_FREE free
# endif
-#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-#if (! defined (yyoverflow) \
- && (! defined (__cplusplus) \
- || (YYSTYPE_IS_TRIVIAL)))
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- short yyss;
- YYSTYPE yyvs;
- };
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -271,24 +421,24 @@ union yyalloc
/* The size of an array large to enough to hold all stacks, each with
N elements. */
# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
/* Copy COUNT objects from FROM to TO. The source and destination do
not overlap. */
# ifndef YYCOPY
-# if 1 < __GNUC__
+# if defined __GNUC__ && 1 < __GNUC__
# define YYCOPY(To, From, Count) \
__builtin_memcpy (To, From, (Count) * sizeof (*(From)))
# else
# define YYCOPY(To, From, Count) \
do \
{ \
- register YYSIZE_T yyi; \
+ YYSIZE_T yyi; \
for (yyi = 0; yyi < (Count); yyi++) \
(To)[yyi] = (From)[yyi]; \
} \
- while (0)
+ while (YYID (0))
# endif
# endif
@@ -297,48 +447,42 @@ union yyalloc
elements in the stack, and YYPTR gives the new location of the
stack. Advance YYPTR to a properly aligned location for the next
stack. */
-# define YYSTACK_RELOCATE(Stack) \
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
do \
{ \
YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
- while (0)
-
-#endif
+ while (YYID (0))
-#if defined (__STDC__) || defined (__cplusplus)
- typedef signed char yysigned_char;
-#else
- typedef short yysigned_char;
#endif
-/* YYFINAL -- State number of the termination state. */
+/* YYFINAL -- State number of the termination state. */
#define YYFINAL 43
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 261
+#define YYLAST 243
-/* YYNTOKENS -- Number of terminals. */
+/* YYNTOKENS -- Number of terminals. */
#define YYNTOKENS 49
-/* YYNNTS -- Number of nonterminals. */
+/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 24
-/* YYNRULES -- Number of rules. */
+/* YYNRULES -- Number of rules. */
#define YYNRULES 75
-/* YYNRULES -- Number of states. */
+/* YYNRULES -- Number of states. */
#define YYNSTATES 159
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
#define YYMAXUTOK 303
-#define YYTRANSLATE(YYX) \
+#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
-static const unsigned char yytranslate[] =
+static const yytype_uint8 yytranslate[] =
{
0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -376,7 +520,7 @@ static const unsigned char yytranslate[] =
#if YYDEBUG
/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
YYRHS. */
-static const unsigned char yyprhs[] =
+static const yytype_uint8 yyprhs[] =
{
0, 0, 3, 4, 6, 8, 10, 12, 15, 21,
22, 25, 27, 31, 32, 34, 35, 39, 43, 47,
@@ -388,8 +532,8 @@ static const unsigned char yyprhs[] =
244, 246, 248, 250, 252, 253
};
-/* YYRHS -- A `-1'-separated list of the rules' RHS. */
-static const yysigned_char yyrhs[] =
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int8 yyrhs[] =
{
50, 0, -1, -1, 52, -1, 53, -1, 52, -1,
57, -1, 57, 52, -1, 32, 65, 54, 11, 51,
@@ -413,14 +557,14 @@ static const yysigned_char yyrhs[] =
7, 61, 8, -1, -1, 63, 62, -1, 22, 47,
10, 51, -1, 65, -1, 65, 10, 64, -1, 66,
-1, -1, 66, 67, -1, 47, -1, -1, 18, 68,
- 69, 19, -1, 67, 64, -1, 34, 67, 67, 64,
+ 69, 19, -1, 47, 64, -1, 34, 67, 47, 64,
-1, 34, 67, 37, 65, -1, -1, 70, 71, -1,
41, -1, 40, -1, 29, -1, 36, -1, 35, -1,
26, -1, -1, 21, 65, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const unsigned short yyrline[] =
+static const yytype_uint16 yyrline[] =
{
0, 139, 139, 141, 152, 154, 158, 160, 162, 167,
170, 172, 176, 179, 182, 185, 188, 190, 192, 194,
@@ -433,9 +577,9 @@ static const unsigned short yyrline[] =
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE
-/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
- First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
{
"$end", "error", "$undefined", "_BANG_t", "_BANG_EQUALS_t", "_AMPER_t",
@@ -448,15 +592,15 @@ static const char *const yytname[] =
"RULE_t", "SWITCH_t", "TOGETHER_t", "UPDATED_t", "WHILE_t", "_LBRACE_t",
"_BAR_t", "_BARBAR_t", "_RBRACE_t", "ARG", "STRING", "$accept", "run",
"block", "rules", "null", "assign_list_opt", "arglist_opt", "local_opt",
- "rule", "@1", "@2", "assign", "expr", "cases", "case", "lol", "list",
- "listp", "arg", "@3", "func", "eflags", "eflag", "bindlist", 0
+ "rule", "$@1", "$@2", "assign", "expr", "cases", "case", "lol", "list",
+ "listp", "arg", "$@3", "func", "eflags", "eflag", "bindlist", 0
};
#endif
# ifdef YYPRINT
/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
token YYLEX-NUM. */
-static const unsigned short yytoknum[] =
+static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
@@ -467,7 +611,7 @@ static const unsigned short yytoknum[] =
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const unsigned char yyr1[] =
+static const yytype_uint8 yyr1[] =
{
0, 49, 50, 50, 51, 51, 52, 52, 52, 53,
54, 54, 55, 55, 56, 56, 57, 57, 57, 57,
@@ -480,7 +624,7 @@ static const unsigned char yyr1[] =
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const unsigned char yyr2[] =
+static const yytype_uint8 yyr2[] =
{
0, 2, 0, 1, 1, 1, 1, 2, 5, 0,
2, 1, 3, 0, 1, 0, 3, 3, 3, 4,
@@ -495,7 +639,7 @@ static const unsigned char yyr2[] =
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
-static const unsigned char yydefact[] =
+static const yytype_uint8 yydefact[] =
{
2, 61, 66, 58, 15, 0, 58, 58, 58, 0,
58, 58, 0, 9, 60, 0, 3, 0, 6, 0,
@@ -515,8 +659,8 @@ static const unsigned char yydefact[] =
12, 20, 32, 0, 28, 54, 0, 22, 33
};
-/* YYDEFGOTO[NTERM-NUM]. */
-static const short yydefgoto[] =
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
{
-1, 15, 39, 40, 41, 84, 125, 17, 18, 146,
156, 51, 30, 121, 122, 22, 23, 24, 31, 20,
@@ -526,31 +670,31 @@ static const short yydefgoto[] =
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
#define YYPACT_NINF -48
-static const short yypact[] =
+static const yytype_int16 yypact[] =
{
- 179, -48, -48, -48, -15, 7, -48, -16, -48, 3,
- -48, -48, 7, 179, 1, 27, -48, -9, 179, 19,
- -3, 33, -11, 24, 3, -48, -10, 7, 7, -48,
- 138, 9, 30, 35, 13, 205, 53, 22, 151, 20,
- -48, -48, 56, -48, 23, -48, -48, -48, -48, 61,
- -48, -48, 3, -48, 62, -48, -48, -48, -48, -48,
- -48, 58, -48, 179, -48, -48, 52, -48, 164, 7,
- 7, 7, 7, 7, 7, 7, 7, 179, 7, 7,
- -48, -48, -48, -48, 72, 179, -48, -48, 68, 179,
- -48, -48, 85, -48, 77, 73, 8, -48, -48, -48,
- 50, 57, -48, -48, -48, 45, 93, 93, -48, -48,
- 45, -48, -48, 64, 245, 245, -48, -48, 179, 66,
- 67, 69, 68, 71, -48, 205, -48, -48, -48, -48,
- -48, -48, -48, 70, 79, -48, -48, 109, -48, -48,
- -48, 112, -48, 115, -48, -48, 75, 179, 205, 179,
- -48, -48, -48, 81, -48, -48, 82, -48, -48
+ 170, -48, -48, -48, -12, 7, -48, -17, -48, -3,
+ -48, -48, 7, 170, 1, 22, -48, -9, 170, 19,
+ -2, 79, -6, 29, -3, -48, 2, 7, 7, -48,
+ 138, 20, 44, 45, 18, 196, 51, 26, 151, 24,
+ -48, -48, 62, -48, 27, -48, -48, -48, -48, 61,
+ -48, -48, -3, -48, 67, -48, -48, -48, -48, -48,
+ -48, 58, -48, 170, -48, -48, 50, -48, 52, 7,
+ 7, 7, 7, 7, 7, 7, 7, 170, 7, 7,
+ -48, -48, -48, -48, 70, 170, -48, -48, 87, 170,
+ -48, -48, 94, -48, 17, 99, -20, -48, -48, -48,
+ 69, 71, -48, -48, -48, 91, 156, 156, -48, -48,
+ 91, -48, -48, 77, 78, 78, -48, -48, 170, 81,
+ 66, 82, 87, 95, -48, 196, -48, -48, -48, -48,
+ -48, -48, -48, 97, 112, -48, -48, 135, -48, -48,
+ -48, 150, -48, 148, -48, -48, 98, 170, 196, 170,
+ -48, -48, -48, 115, -48, -48, 116, -48, -48
};
/* YYPGOTO[NTERM-NUM]. */
-static const short yypgoto[] =
+static const yytype_int16 yypgoto[] =
{
- -48, -48, -47, 5, 104, -48, -48, 136, -27, -48,
- -48, 47, 60, 36, -48, -13, -4, -48, 0, -48,
+ -48, -48, -47, 5, 140, -48, -48, 171, -27, -48,
+ -48, 80, 60, 54, -48, -13, -4, -48, 0, -48,
-48, -48, -48, -48
};
@@ -559,106 +703,86 @@ static const short yypgoto[] =
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -59
-static const short yytable[] =
+static const yytype_int16 yytable[] =
{
19, 42, 32, 33, 34, 16, 36, 37, 86, 35,
- 27, -58, -58, 19, 28, 1, 101, 25, 19, -58,
- 53, 1, -14, 45, 65, 1, 1, 43, 46, 44,
- 113, 52, 63, 47, 64, 19, 48, 66, 119, 80,
- 97, 81, 123, 49, 29, 128, 94, 95, -58, 82,
- 29, 102, 96, 50, 29, 29, 85, 72, 73, 55,
- 75, 76, 56, 19, 87, 88, 90, 91, 57, 58,
- 92, 135, 38, 59, 60, 93, 116, 19, 117, 99,
- 61, 98, 103, 118, 127, 19, 46, 67, 68, 19,
- 120, 47, 124, 131, 48, 130, 129, 69, 142, 133,
- 153, 49, 155, 132, 148, 72, 73, 74, 75, 76,
- 134, 141, 136, 147, 137, 138, 145, 140, 19, 149,
- 150, 154, 143, 152, 144, 19, 151, 157, 158, 105,
- 106, 107, 108, 109, 110, 111, 112, 83, 114, 115,
- 26, 126, 69, 70, 71, 0, 0, 19, 19, 19,
- 72, 73, 74, 75, 76, 69, 70, 71, 139, 0,
- 0, 0, 0, 72, 73, 74, 75, 76, 69, 70,
- 71, 0, 104, 0, 0, 0, 72, 73, 74, 75,
- 76, 77, 78, 79, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 89, 78, 79, 1, 0, 2,
- 0, 0, 3, 0, 0, 0, 4, 5, 78, 79,
- 6, 7, 8, 9, 0, 0, 10, -15, 11, 0,
- 0, 12, 13, 1, 0, 2, 14, 0, 3, 0,
- 0, 0, 4, 5, 0, 0, 6, 25, 8, 9,
- 0, 0, 10, 0, 11, 0, 0, 12, 13, 69,
- 70, 71, 14, 0, 0, 0, 0, 72, 73, 74,
- 75, 76
+ 27, -58, -58, 19, 28, 1, 101, 128, 19, -58,
+ 25, -14, 43, 45, 65, 1, 46, 129, 46, 44,
+ 113, 47, 52, 47, 48, 19, 48, 63, 119, 64,
+ 97, 49, 123, 49, 29, 53, 94, 95, -58, 66,
+ 80, 102, 96, 50, 29, 81, 69, 70, 71, 82,
+ 104, 85, 87, 19, 72, 73, 74, 75, 76, 88,
+ 90, 135, 38, 91, 92, 93, 116, 19, 117, 99,
+ 103, 118, 69, 70, 71, 19, 98, 67, 68, 19,
+ 72, 73, 74, 75, 76, 130, 78, 79, 142, 133,
+ 153, 124, 155, 72, 73, 55, 75, 76, 56, 120,
+ 127, 141, 131, 137, 57, 58, 145, 132, 19, 59,
+ 60, 154, 143, 134, 144, 19, 61, 136, 138, 105,
+ 106, 107, 108, 109, 110, 111, 112, 148, 114, 115,
+ 147, 140, 69, 70, 71, 149, 152, 19, 19, 19,
+ 72, 73, 74, 75, 76, 69, 70, 71, 150, 151,
+ 69, 157, 158, 72, 73, 74, 75, 76, 72, 73,
+ 74, 75, 76, 83, 126, 26, 139, 0, 0, 0,
+ 0, 77, 78, 79, 0, 0, 0, 0, 1, 0,
+ 2, 0, 0, 3, 89, 78, 79, 4, 5, 0,
+ 0, 6, 7, 8, 9, 0, 0, 10, -15, 11,
+ 0, 0, 12, 13, 1, 0, 2, 14, 0, 3,
+ 0, 0, 0, 4, 5, 0, 0, 6, 25, 8,
+ 9, 0, 0, 10, 0, 11, 0, 0, 12, 13,
+ 0, 0, 0, 14
};
-static const short yycheck[] =
+static const yytype_int16 yycheck[] =
{
0, 14, 6, 7, 8, 0, 10, 11, 35, 9,
- 3, 10, 11, 13, 7, 18, 63, 32, 18, 18,
- 20, 18, 38, 18, 24, 18, 18, 0, 9, 38,
- 77, 34, 43, 14, 10, 35, 17, 47, 85, 30,
- 53, 11, 89, 24, 47, 37, 50, 51, 47, 14,
- 47, 64, 52, 34, 47, 47, 43, 12, 13, 26,
- 15, 16, 29, 63, 11, 43, 46, 11, 35, 36,
- 47, 118, 12, 40, 41, 14, 80, 77, 82, 21,
- 47, 19, 30, 11, 11, 85, 9, 27, 28, 89,
- 22, 14, 7, 43, 17, 99, 96, 4, 125, 103,
- 147, 24, 149, 46, 25, 12, 13, 14, 15, 16,
- 46, 124, 46, 43, 47, 46, 129, 46, 118, 10,
- 8, 148, 126, 48, 128, 125, 11, 46, 46, 69,
- 70, 71, 72, 73, 74, 75, 76, 33, 78, 79,
- 4, 94, 4, 5, 6, -1, -1, 147, 148, 149,
- 12, 13, 14, 15, 16, 4, 5, 6, 122, -1,
- -1, -1, -1, 12, 13, 14, 15, 16, 4, 5,
- 6, -1, 8, -1, -1, -1, 12, 13, 14, 15,
- 16, 43, 44, 45, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, 43, 44, 45, 18, -1, 20,
- -1, -1, 23, -1, -1, -1, 27, 28, 44, 45,
- 31, 32, 33, 34, -1, -1, 37, 38, 39, -1,
- -1, 42, 43, 18, -1, 20, 47, -1, 23, -1,
- -1, -1, 27, 28, -1, -1, 31, 32, 33, 34,
- -1, -1, 37, -1, 39, -1, -1, 42, 43, 4,
- 5, 6, 47, -1, -1, -1, -1, 12, 13, 14,
- 15, 16
+ 3, 10, 11, 13, 7, 18, 63, 37, 18, 18,
+ 32, 38, 0, 18, 24, 18, 9, 47, 9, 38,
+ 77, 14, 34, 14, 17, 35, 17, 43, 85, 10,
+ 53, 24, 89, 24, 47, 47, 50, 51, 47, 47,
+ 30, 64, 52, 34, 47, 11, 4, 5, 6, 14,
+ 8, 43, 11, 63, 12, 13, 14, 15, 16, 43,
+ 46, 118, 12, 11, 47, 14, 80, 77, 82, 21,
+ 30, 11, 4, 5, 6, 85, 19, 27, 28, 89,
+ 12, 13, 14, 15, 16, 99, 44, 45, 125, 103,
+ 147, 7, 149, 12, 13, 26, 15, 16, 29, 22,
+ 11, 124, 43, 47, 35, 36, 129, 46, 118, 40,
+ 41, 148, 126, 46, 128, 125, 47, 46, 46, 69,
+ 70, 71, 72, 73, 74, 75, 76, 25, 78, 79,
+ 43, 46, 4, 5, 6, 10, 48, 147, 148, 149,
+ 12, 13, 14, 15, 16, 4, 5, 6, 8, 11,
+ 4, 46, 46, 12, 13, 14, 15, 16, 12, 13,
+ 14, 15, 16, 33, 94, 4, 122, -1, -1, -1,
+ -1, 43, 44, 45, -1, -1, -1, -1, 18, -1,
+ 20, -1, -1, 23, 43, 44, 45, 27, 28, -1,
+ -1, 31, 32, 33, 34, -1, -1, 37, 38, 39,
+ -1, -1, 42, 43, 18, -1, 20, 47, -1, 23,
+ -1, -1, -1, 27, 28, -1, -1, 31, 32, 33,
+ 34, -1, -1, 37, -1, 39, -1, -1, 42, 43,
+ -1, -1, -1, 47
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
-static const unsigned char yystos[] =
+static const yytype_uint8 yystos[] =
{
0, 18, 20, 23, 27, 28, 31, 32, 33, 34,
37, 39, 42, 43, 47, 50, 52, 56, 57, 67,
68, 70, 64, 65, 66, 32, 56, 3, 7, 47,
61, 67, 65, 65, 65, 67, 65, 65, 61, 51,
52, 53, 64, 0, 38, 52, 9, 14, 17, 24,
- 34, 60, 34, 67, 69, 26, 29, 35, 36, 40,
+ 34, 60, 34, 47, 69, 26, 29, 35, 36, 40,
41, 47, 71, 43, 10, 67, 47, 61, 61, 4,
5, 6, 12, 13, 14, 15, 16, 43, 44, 45,
30, 11, 14, 53, 54, 43, 57, 11, 43, 43,
46, 11, 47, 14, 65, 65, 67, 64, 19, 21,
72, 51, 64, 30, 8, 61, 61, 61, 61, 61,
61, 61, 61, 51, 61, 61, 65, 65, 11, 51,
- 22, 62, 63, 51, 7, 55, 60, 11, 37, 67,
+ 22, 62, 63, 51, 7, 55, 60, 11, 37, 47,
65, 43, 46, 65, 46, 51, 46, 47, 46, 62,
46, 64, 57, 65, 65, 64, 58, 43, 25, 10,
8, 11, 48, 51, 57, 51, 59, 46, 46
};
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
#define yyerrok (yyerrstatus = 0)
#define yyclearin (yychar = YYEMPTY)
#define YYEMPTY (-2)
@@ -666,13 +790,23 @@ static const unsigned char yystos[] =
#define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrlab1
+#define YYERROR goto yyerrorlab
+
/* Like YYERROR except do call yyerror. This remains here temporarily
to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
#define YYRECOVERING() (!!yyerrstatus)
@@ -683,30 +817,63 @@ do \
yychar = (Token); \
yylval = (Value); \
yytoken = YYTRANSLATE (yychar); \
- YYPOPSTACK; \
+ YYPOPSTACK (1); \
goto yybackup; \
} \
else \
- { \
- yyerror ("syntax error: cannot back up");\
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
-while (0)
+while (YYID (0))
+
#define YYTERROR 1
#define YYERRCODE 256
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
- are run). */
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- Current.first_line = Rhs[1].first_line; \
- Current.first_column = Rhs[1].first_column; \
- Current.last_line = Rhs[N].last_line; \
- Current.last_column = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
#endif
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
/* YYLEX -- calling `yylex' with the right arguments. */
#ifdef YYLEX_PARAM
@@ -727,43 +894,100 @@ while (0)
do { \
if (yydebug) \
YYFPRINTF Args; \
-} while (0)
+} while (YYID (0))
-# define YYDSYMPRINT(Args) \
-do { \
- if (yydebug) \
- yysymprint Args; \
-} while (0)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
-# define YYDSYMPRINTF(Title, Token, Value, Location) \
-do { \
- if (yydebug) \
- { \
- YYFPRINTF (stderr, "%s ", Title); \
- yysymprint (stderr, \
- Token, Value); \
- YYFPRINTF (stderr, "\n"); \
- } \
-} while (0)
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
/*------------------------------------------------------------------.
| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (cinluded). |
+| TOP (included). |
`------------------------------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (short *bottom, short *top)
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
#else
static void
-yy_stack_print (bottom, top)
- short *bottom;
- short *top;
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (/* Nothing. */; bottom <= top; ++bottom)
- YYFPRINTF (stderr, " %d", *bottom);
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
YYFPRINTF (stderr, "\n");
}
@@ -771,45 +995,52 @@ yy_stack_print (bottom, top)
do { \
if (yydebug) \
yy_stack_print ((Bottom), (Top)); \
-} while (0)
+} while (YYID (0))
/*------------------------------------------------.
| Report that the YYRULE is going to be reduced. |
`------------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yy_reduce_print (int yyrule)
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
#else
static void
-yy_reduce_print (yyrule)
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
int yyrule;
#endif
{
+ int yynrhs = yyr2[yyrule];
int yyi;
- unsigned int yylineno = yyrline[yyrule];
- YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
- yyrule - 1, yylineno);
- /* Print the symbols being reduced, and their result. */
- for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
- YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
- YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
}
# define YY_REDUCE_PRINT(Rule) \
do { \
if (yydebug) \
- yy_reduce_print (Rule); \
-} while (0)
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
/* Nonzero means print parse trace. It is left uninitialized so that
multiple parsers can coexist. */
int yydebug;
#else /* !YYDEBUG */
# define YYDPRINTF(Args)
-# define YYDSYMPRINT(Args)
-# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
# define YY_STACK_PRINT(Bottom, Top)
# define YY_REDUCE_PRINT(Rule)
#endif /* !YYDEBUG */
@@ -824,13 +1055,9 @@ int yydebug;
if the built-in stack extension method is used).
Do not make this value too large; the results are undefined if
- SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
evaluated with infinite-precision integer arithmetic. */
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
#ifndef YYMAXDEPTH
# define YYMAXDEPTH 10000
#endif
@@ -840,45 +1067,47 @@ int yydebug;
#if YYERROR_VERBOSE
# ifndef yystrlen
-# if defined (__GLIBC__) && defined (_STRING_H)
+# if defined __GLIBC__ && defined _STRING_H
# define yystrlen strlen
# else
/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static YYSIZE_T
-# if defined (__STDC__) || defined (__cplusplus)
yystrlen (const char *yystr)
-# else
+#else
+static YYSIZE_T
yystrlen (yystr)
- const char *yystr;
-# endif
+ const char *yystr;
+#endif
{
- register const char *yys = yystr;
-
- while (*yys++ != '\0')
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
continue;
-
- return yys - yystr - 1;
+ return yylen;
}
# endif
# endif
# ifndef yystpcpy
-# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
# define yystpcpy stpcpy
# else
/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static char *
-# if defined (__STDC__) || defined (__cplusplus)
yystpcpy (char *yydest, const char *yysrc)
-# else
+#else
+static char *
yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-# endif
+ char *yydest;
+ const char *yysrc;
+#endif
{
- register char *yyd = yydest;
- register const char *yys = yysrc;
+ char *yyd = yydest;
+ const char *yys = yysrc;
while ((*yyd++ = *yys++) != '\0')
continue;
@@ -888,84 +1117,204 @@ yystpcpy (yydest, yysrc)
# endif
# endif
-#endif /* !YYERROR_VERBOSE */
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
-
+ if (! yyres)
+ return yystrlen (yystr);
-#if YYDEBUG
-/*--------------------------------.
-| Print this symbol on YYOUTPUT. |
-`--------------------------------*/
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
-#if defined (__STDC__) || defined (__cplusplus)
-static void
-yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yysymprint (yyoutput, yytype, yyvaluep)
- FILE *yyoutput;
- int yytype;
- YYSTYPE *yyvaluep;
-#endif
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- /* Pacify ``unused variable'' warnings. */
- (void) yyvaluep;
+ int yyn = yypact[yystate];
- if (yytype < YYNTOKENS)
- {
- YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-# ifdef YYPRINT
- YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# endif
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
else
- YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
- switch (yytype)
{
- default:
- break;
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
}
- YYFPRINTF (yyoutput, ")");
}
+#endif /* YYERROR_VERBOSE */
+
-#endif /* ! YYDEBUG */
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
`-----------------------------------------------*/
-#if defined (__STDC__) || defined (__cplusplus)
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
static void
-yydestruct (int yytype, YYSTYPE *yyvaluep)
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
#else
static void
-yydestruct (yytype, yyvaluep)
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
int yytype;
YYSTYPE *yyvaluep;
#endif
{
- /* Pacify ``unused variable'' warnings. */
- (void) yyvaluep;
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
switch (yytype)
{
default:
- break;
+ break;
}
}
-
/* Prevent warnings from -Wmissing-prototypes. */
-
#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
+#if defined __STDC__ || defined __cplusplus
int yyparse (void *YYPARSE_PARAM);
-# else
+#else
int yyparse ();
-# endif
+#endif
#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
+#if defined __STDC__ || defined __cplusplus
int yyparse (void);
#else
int yyparse ();
@@ -973,7 +1322,6 @@ int yyparse ();
#endif /* ! YYPARSE_PARAM */
-
/* The lookahead symbol. */
int yychar;
@@ -985,19 +1333,23 @@ int yynerrs;
-/*----------.
-| yyparse. |
-`----------*/
+/*-------------------------.
+| yyparse or yypush_parse. |
+`-------------------------*/
#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-int yyparse (void *YYPARSE_PARAM)
-# else
-int yyparse (YYPARSE_PARAM)
- void *YYPARSE_PARAM;
-# endif
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
#else /* ! YYPARSE_PARAM */
-#if defined (__STDC__) || defined (__cplusplus)
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
int
yyparse (void)
#else
@@ -1008,59 +1360,67 @@ yyparse ()
#endif
{
- register int yystate;
- register int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Lookahead token as an internal (translated) token number. */
- int yytoken = 0;
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
- /* The state stack. */
- short yyssa[YYINITDEPTH];
- short *yyss = yyssa;
- register short *yyssp;
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- register YYSTYPE *yyvsp;
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
-#define YYPOPSTACK (yyvsp--, yyssp--)
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
- YYSIZE_T yystacksize = YYINITDEPTH;
+ YYSIZE_T yystacksize;
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
/* The variables used to return semantic value and location from the
action routines. */
YYSTYPE yyval;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
- /* When reducing, the number of symbols on the RHS of the reduced
- rule. */
- int yylen;
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ yychar = YYEMPTY; /* Cause a token to be read. */
/* Initialize stack pointers.
Waste one element of value and location stack
so that they stay on the same level as the state stack.
The wasted elements are never initialized. */
-
yyssp = yyss;
yyvsp = yyvs;
@@ -1071,8 +1431,7 @@ yyparse ()
`------------------------------------------------------------*/
yynewstate:
/* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks.
- */
+ have just been pushed. So pushing a state here evens the stacks. */
yyssp++;
yysetstate:
@@ -1085,21 +1444,19 @@ yyparse ()
#ifdef yyoverflow
{
- /* Give user a chance to reallocate the stack. Use copies of
+ /* Give user a chance to reallocate the stack. Use copies of
these so that the &'s don't force the real ones into
memory. */
YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-
+ yytype_int16 *yyss1 = yyss;
/* Each stack pointer address is followed by the size of the
data in use in that stack, in bytes. This used to be a
conditional around just the two extra args, but that might
be undefined if yyoverflow is a macro. */
- yyoverflow ("parser stack overflow",
+ yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
-
&yystacksize);
yyss = yyss1;
@@ -1107,24 +1464,23 @@ yyparse ()
}
#else /* no yyoverflow */
# ifndef YYSTACK_RELOCATE
- goto yyoverflowlab;
+ goto yyexhaustedlab;
# else
/* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize)
- goto yyoverflowlab;
+ goto yyexhaustedlab;
yystacksize *= 2;
if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH;
{
- short *yyss1 = yyss;
+ yytype_int16 *yyss1 = yyss;
union yyalloc *yyptr =
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
- goto yyoverflowlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1135,7 +1491,6 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
-
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1145,6 +1500,9 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
goto yybackup;
/*-----------.
@@ -1152,12 +1510,10 @@ yyparse ()
`-----------*/
yybackup:
-/* Do appropriate processing given the current state. */
-/* Read a lookahead token if we need one and don't already have one. */
-/* yyresume: */
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
/* First try to decide what to do without reference to lookahead token. */
-
yyn = yypact[yystate];
if (yyn == YYPACT_NINF)
goto yydefault;
@@ -1179,7 +1535,7 @@ yybackup:
else
{
yytoken = YYTRANSLATE (yychar);
- YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
}
/* If the proper action on seeing token YYTOKEN is to reduce or to
@@ -1196,25 +1552,20 @@ yybackup:
goto yyreduce;
}
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Shift the lookahead token. */
- YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
-
- /* Discard the token being shifted unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- *++yyvsp = yylval;
-
-
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
yystate = yyn;
+ *++yyvsp = yylval;
+
goto yynewstate;
@@ -1250,385 +1601,530 @@ yyreduce:
switch (yyn)
{
case 3:
+
+/* Line 1464 of yacc.c */
#line 142 "jamgram.y"
- { parse_save( yyvsp[0].parse ); }
+ { parse_save( (yyvsp[(1) - (1)]).parse ); }
break;
case 4:
+
+/* Line 1464 of yacc.c */
#line 153 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 5:
+
+/* Line 1464 of yacc.c */
#line 155 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 6:
+
+/* Line 1464 of yacc.c */
#line 159 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; }
break;
case 7:
+
+/* Line 1464 of yacc.c */
#line 161 "jamgram.y"
- { yyval.parse = prules( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = prules( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 8:
+
+/* Line 1464 of yacc.c */
#line 163 "jamgram.y"
- { yyval.parse = plocal( yyvsp[-3].parse, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = plocal( (yyvsp[(2) - (5)]).parse, (yyvsp[(3) - (5)]).parse, (yyvsp[(5) - (5)]).parse ); }
break;
case 9:
+
+/* Line 1464 of yacc.c */
#line 167 "jamgram.y"
- { yyval.parse = pnull(); }
+ { (yyval).parse = pnull(); }
break;
case 10:
+
+/* Line 1464 of yacc.c */
#line 171 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_SET; }
+ { (yyval).parse = (yyvsp[(2) - (2)]).parse; (yyval).number = ASSIGN_SET; }
break;
case 11:
+
+/* Line 1464 of yacc.c */
#line 173 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yyval.number = ASSIGN_APPEND; }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; (yyval).number = ASSIGN_APPEND; }
break;
case 12:
+
+/* Line 1464 of yacc.c */
#line 177 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 13:
+
+/* Line 1464 of yacc.c */
#line 179 "jamgram.y"
- { yyval.parse = P0; }
+ { (yyval).parse = P0; }
break;
case 14:
+
+/* Line 1464 of yacc.c */
#line 183 "jamgram.y"
- { yyval.number = 1; }
+ { (yyval).number = 1; }
break;
case 15:
+
+/* Line 1464 of yacc.c */
#line 185 "jamgram.y"
- { yyval.number = 0; }
+ { (yyval).number = 0; }
break;
case 16:
+
+/* Line 1464 of yacc.c */
#line 189 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 17:
+
+/* Line 1464 of yacc.c */
#line 191 "jamgram.y"
- { yyval.parse = pincl( yyvsp[-1].parse ); }
+ { (yyval).parse = pincl( (yyvsp[(2) - (3)]).parse ); }
break;
case 18:
+
+/* Line 1464 of yacc.c */
#line 193 "jamgram.y"
- { yyval.parse = prule( yyvsp[-2].string, yyvsp[-1].parse ); }
+ { (yyval).parse = prule( (yyvsp[(1) - (3)]).string, (yyvsp[(2) - (3)]).parse ); }
break;
case 19:
+
+/* Line 1464 of yacc.c */
#line 195 "jamgram.y"
- { yyval.parse = pset( yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
+ { (yyval).parse = pset( (yyvsp[(1) - (4)]).parse, (yyvsp[(3) - (4)]).parse, (yyvsp[(2) - (4)]).number ); }
break;
case 20:
+
+/* Line 1464 of yacc.c */
#line 197 "jamgram.y"
- { yyval.parse = pset1( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-2].number ); }
+ { (yyval).parse = pset1( (yyvsp[(1) - (6)]).parse, (yyvsp[(3) - (6)]).parse, (yyvsp[(5) - (6)]).parse, (yyvsp[(4) - (6)]).number ); }
break;
case 21:
+
+/* Line 1464 of yacc.c */
#line 199 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 22:
+
+/* Line 1464 of yacc.c */
#line 201 "jamgram.y"
- { yyval.parse = pfor( yyvsp[-5].string, yyvsp[-3].parse, yyvsp[-1].parse, yyvsp[-6].number ); }
+ { (yyval).parse = pfor( (yyvsp[(3) - (8)]).string, (yyvsp[(5) - (8)]).parse, (yyvsp[(7) - (8)]).parse, (yyvsp[(2) - (8)]).number ); }
break;
case 23:
+
+/* Line 1464 of yacc.c */
#line 203 "jamgram.y"
- { yyval.parse = pswitch( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pswitch( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 24:
+
+/* Line 1464 of yacc.c */
#line 205 "jamgram.y"
- { yyval.parse = pif( yyvsp[-3].parse, yyvsp[-1].parse, pnull() ); }
+ { (yyval).parse = pif( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse, pnull() ); }
break;
case 25:
+
+/* Line 1464 of yacc.c */
#line 207 "jamgram.y"
- { yyval.parse = pmodule( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pmodule( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 26:
+
+/* Line 1464 of yacc.c */
#line 209 "jamgram.y"
- { yyval.parse = pclass( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pclass( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 27:
+
+/* Line 1464 of yacc.c */
#line 211 "jamgram.y"
- { yyval.parse = pwhile( yyvsp[-3].parse, yyvsp[-1].parse ); }
+ { (yyval).parse = pwhile( (yyvsp[(2) - (5)]).parse, (yyvsp[(4) - (5)]).parse ); }
break;
case 28:
+
+/* Line 1464 of yacc.c */
#line 213 "jamgram.y"
- { yyval.parse = pif( yyvsp[-5].parse, yyvsp[-3].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pif( (yyvsp[(2) - (7)]).parse, (yyvsp[(4) - (7)]).parse, (yyvsp[(7) - (7)]).parse ); }
break;
case 29:
+
+/* Line 1464 of yacc.c */
#line 215 "jamgram.y"
- { yyval.parse = psetc( yyvsp[-2].string, yyvsp[0].parse, yyvsp[-1].parse, yyvsp[-4].number ); }
+ { (yyval).parse = psetc( (yyvsp[(3) - (5)]).string, (yyvsp[(5) - (5)]).parse, (yyvsp[(4) - (5)]).parse, (yyvsp[(1) - (5)]).number ); }
break;
case 30:
+
+/* Line 1464 of yacc.c */
#line 217 "jamgram.y"
- { yyval.parse = pon( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 31:
+
+/* Line 1464 of yacc.c */
#line 219 "jamgram.y"
{ yymode( SCAN_STRING ); }
break;
case 32:
+
+/* Line 1464 of yacc.c */
#line 221 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 33:
+
+/* Line 1464 of yacc.c */
#line 223 "jamgram.y"
- { yyval.parse = psete( yyvsp[-6].string,yyvsp[-5].parse,yyvsp[-2].string,yyvsp[-7].number ); }
+ { (yyval).parse = psete( (yyvsp[(3) - (9)]).string,(yyvsp[(4) - (9)]).parse,(yyvsp[(7) - (9)]).string,(yyvsp[(2) - (9)]).number ); }
break;
case 34:
+
+/* Line 1464 of yacc.c */
#line 231 "jamgram.y"
- { yyval.number = ASSIGN_SET; }
+ { (yyval).number = ASSIGN_SET; }
break;
case 35:
+
+/* Line 1464 of yacc.c */
#line 233 "jamgram.y"
- { yyval.number = ASSIGN_APPEND; }
+ { (yyval).number = ASSIGN_APPEND; }
break;
case 36:
+
+/* Line 1464 of yacc.c */
#line 235 "jamgram.y"
- { yyval.number = ASSIGN_DEFAULT; }
+ { (yyval).number = ASSIGN_DEFAULT; }
break;
case 37:
+
+/* Line 1464 of yacc.c */
#line 237 "jamgram.y"
- { yyval.number = ASSIGN_DEFAULT; }
+ { (yyval).number = ASSIGN_DEFAULT; }
break;
case 38:
+
+/* Line 1464 of yacc.c */
#line 244 "jamgram.y"
- { yyval.parse = peval( EXPR_EXISTS, yyvsp[0].parse, pnull() ); }
+ { (yyval).parse = peval( EXPR_EXISTS, (yyvsp[(1) - (1)]).parse, pnull() ); }
break;
case 39:
+
+/* Line 1464 of yacc.c */
#line 246 "jamgram.y"
- { yyval.parse = peval( EXPR_EQUALS, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_EQUALS, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 40:
+
+/* Line 1464 of yacc.c */
#line 248 "jamgram.y"
- { yyval.parse = peval( EXPR_NOTEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_NOTEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 41:
+
+/* Line 1464 of yacc.c */
#line 250 "jamgram.y"
- { yyval.parse = peval( EXPR_LESS, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_LESS, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 42:
+
+/* Line 1464 of yacc.c */
#line 252 "jamgram.y"
- { yyval.parse = peval( EXPR_LESSEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_LESSEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 43:
+
+/* Line 1464 of yacc.c */
#line 254 "jamgram.y"
- { yyval.parse = peval( EXPR_MORE, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_MORE, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 44:
+
+/* Line 1464 of yacc.c */
#line 256 "jamgram.y"
- { yyval.parse = peval( EXPR_MOREEQ, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_MOREEQ, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 45:
+
+/* Line 1464 of yacc.c */
#line 258 "jamgram.y"
- { yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_AND, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 46:
+
+/* Line 1464 of yacc.c */
#line 260 "jamgram.y"
- { yyval.parse = peval( EXPR_AND, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_AND, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 47:
+
+/* Line 1464 of yacc.c */
#line 262 "jamgram.y"
- { yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_OR, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 48:
+
+/* Line 1464 of yacc.c */
#line 264 "jamgram.y"
- { yyval.parse = peval( EXPR_OR, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_OR, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 49:
+
+/* Line 1464 of yacc.c */
#line 266 "jamgram.y"
- { yyval.parse = peval( EXPR_IN, yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = peval( EXPR_IN, (yyvsp[(1) - (3)]).parse, (yyvsp[(3) - (3)]).parse ); }
break;
case 50:
+
+/* Line 1464 of yacc.c */
#line 268 "jamgram.y"
- { yyval.parse = peval( EXPR_NOT, yyvsp[0].parse, pnull() ); }
+ { (yyval).parse = peval( EXPR_NOT, (yyvsp[(2) - (2)]).parse, pnull() ); }
break;
case 51:
+
+/* Line 1464 of yacc.c */
#line 270 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(2) - (3)]).parse; }
break;
case 52:
+
+/* Line 1464 of yacc.c */
#line 281 "jamgram.y"
- { yyval.parse = P0; }
+ { (yyval).parse = P0; }
break;
case 53:
+
+/* Line 1464 of yacc.c */
#line 283 "jamgram.y"
- { yyval.parse = pnode( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pnode( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 54:
+
+/* Line 1464 of yacc.c */
#line 287 "jamgram.y"
- { yyval.parse = psnode( yyvsp[-2].string, yyvsp[0].parse ); }
+ { (yyval).parse = psnode( (yyvsp[(2) - (4)]).string, (yyvsp[(4) - (4)]).parse ); }
break;
case 55:
+
+/* Line 1464 of yacc.c */
#line 296 "jamgram.y"
- { yyval.parse = pnode( P0, yyvsp[0].parse ); }
+ { (yyval).parse = pnode( P0, (yyvsp[(1) - (1)]).parse ); }
break;
case 56:
+
+/* Line 1464 of yacc.c */
#line 298 "jamgram.y"
- { yyval.parse = pnode( yyvsp[0].parse, yyvsp[-2].parse ); }
+ { (yyval).parse = pnode( (yyvsp[(3) - (3)]).parse, (yyvsp[(1) - (3)]).parse ); }
break;
case 57:
+
+/* Line 1464 of yacc.c */
#line 308 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; yymode( SCAN_NORMAL ); }
+ { (yyval).parse = (yyvsp[(1) - (1)]).parse; yymode( SCAN_NORMAL ); }
break;
case 58:
+
+/* Line 1464 of yacc.c */
#line 312 "jamgram.y"
- { yyval.parse = pnull(); yymode( SCAN_PUNCT ); }
+ { (yyval).parse = pnull(); yymode( SCAN_PUNCT ); }
break;
case 59:
+
+/* Line 1464 of yacc.c */
#line 314 "jamgram.y"
- { yyval.parse = pappend( yyvsp[-1].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pappend( (yyvsp[(1) - (2)]).parse, (yyvsp[(2) - (2)]).parse ); }
break;
case 60:
+
+/* Line 1464 of yacc.c */
#line 318 "jamgram.y"
- { yyval.parse = plist( yyvsp[0].string ); }
+ { (yyval).parse = plist( (yyvsp[(1) - (1)]).string ); }
break;
case 61:
+
+/* Line 1464 of yacc.c */
#line 319 "jamgram.y"
{ yymode( SCAN_NORMAL ); }
break;
case 62:
+
+/* Line 1464 of yacc.c */
#line 320 "jamgram.y"
- { yyval.parse = yyvsp[-1].parse; }
+ { (yyval).parse = (yyvsp[(3) - (4)]).parse; }
break;
case 63:
+
+/* Line 1464 of yacc.c */
#line 329 "jamgram.y"
- { yyval.parse = prule( yyvsp[-1].string, yyvsp[0].parse ); }
+ { (yyval).parse = prule( (yyvsp[(1) - (2)]).string, (yyvsp[(2) - (2)]).parse ); }
break;
case 64:
+
+/* Line 1464 of yacc.c */
#line 331 "jamgram.y"
- { yyval.parse = pon( yyvsp[-2].parse, prule( yyvsp[-1].string, yyvsp[0].parse ) ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (4)]).parse, prule( (yyvsp[(3) - (4)]).string, (yyvsp[(4) - (4)]).parse ) ); }
break;
case 65:
+
+/* Line 1464 of yacc.c */
#line 333 "jamgram.y"
- { yyval.parse = pon( yyvsp[-2].parse, yyvsp[0].parse ); }
+ { (yyval).parse = pon( (yyvsp[(2) - (4)]).parse, (yyvsp[(4) - (4)]).parse ); }
break;
case 66:
+
+/* Line 1464 of yacc.c */
#line 343 "jamgram.y"
- { yyval.number = 0; }
+ { (yyval).number = 0; }
break;
case 67:
+
+/* Line 1464 of yacc.c */
#line 345 "jamgram.y"
- { yyval.number = yyvsp[-1].number | yyvsp[0].number; }
+ { (yyval).number = (yyvsp[(1) - (2)]).number | (yyvsp[(2) - (2)]).number; }
break;
case 68:
+
+/* Line 1464 of yacc.c */
#line 349 "jamgram.y"
- { yyval.number = EXEC_UPDATED; }
+ { (yyval).number = EXEC_UPDATED; }
break;
case 69:
+
+/* Line 1464 of yacc.c */
#line 351 "jamgram.y"
- { yyval.number = EXEC_TOGETHER; }
+ { (yyval).number = EXEC_TOGETHER; }
break;
case 70:
+
+/* Line 1464 of yacc.c */
#line 353 "jamgram.y"
- { yyval.number = EXEC_IGNORE; }
+ { (yyval).number = EXEC_IGNORE; }
break;
case 71:
+
+/* Line 1464 of yacc.c */
#line 355 "jamgram.y"
- { yyval.number = EXEC_QUIETLY; }
+ { (yyval).number = EXEC_QUIETLY; }
break;
case 72:
+
+/* Line 1464 of yacc.c */
#line 357 "jamgram.y"
- { yyval.number = EXEC_PIECEMEAL; }
+ { (yyval).number = EXEC_PIECEMEAL; }
break;
case 73:
+
+/* Line 1464 of yacc.c */
#line 359 "jamgram.y"
- { yyval.number = EXEC_EXISTING; }
+ { (yyval).number = EXEC_EXISTING; }
break;
case 74:
+
+/* Line 1464 of yacc.c */
#line 368 "jamgram.y"
- { yyval.parse = pnull(); }
+ { (yyval).parse = pnull(); }
break;
case 75:
+
+/* Line 1464 of yacc.c */
#line 370 "jamgram.y"
- { yyval.parse = yyvsp[0].parse; }
+ { (yyval).parse = (yyvsp[(2) - (2)]).parse; }
break;
- }
-
-/* Line 991 of yacc.c. */
-#line 1621 "y.tab.c"
-
- yyvsp -= yylen;
- yyssp -= yylen;
+/* Line 1464 of yacc.c */
+#line 2118 "y.tab.c"
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+ YYPOPSTACK (yylen);
+ yylen = 0;
YY_STACK_PRINT (yyss, yyssp);
*++yyvsp = yyval;
-
/* Now `shift' the result of the reduction. Determine what state
that goes to, based on the state we popped back to and the rule
number reduced by. */
@@ -1652,54 +2148,41 @@ yyerrlab:
if (!yyerrstatus)
{
++yynerrs;
-#if YYERROR_VERBOSE
- yyn = yypact[yystate];
-
- if (YYPACT_NINF < yyn && yyn < YYLAST)
- {
- YYSIZE_T yysize = 0;
- int yytype = YYTRANSLATE (yychar);
- char *yymsg;
- int yyx, yycount;
-
- yycount = 0;
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- yysize += yystrlen (yytname[yyx]) + 15, yycount++;
- yysize += yystrlen ("syntax error, unexpected ") + 1;
- yysize += yystrlen (yytname[yytype]);
- yymsg = (char *) YYSTACK_ALLOC (yysize);
- if (yymsg != 0)
- {
- char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
- yyp = yystpcpy (yyp, yytname[yytype]);
-
- if (yycount < 5)
- {
- yycount = 0;
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *));
- yyx++)
- if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
- {
- const char *yyq = ! yycount ? ", expecting " : " or ";
- yyp = yystpcpy (yyp, yyq);
- yyp = yystpcpy (yyp, yytname[yyx]);
- yycount++;
- }
- }
- yyerror (yymsg);
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
- }
- else
- yyerror ("syntax error; also virtual memory exhausted");
- }
- else
-#endif /* YYERROR_VERBOSE */
- yyerror ("syntax error");
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
}
@@ -1709,51 +2192,49 @@ yyerrlab:
/* If just tried and failed to reuse lookahead token after an
error, discard it. */
- /* Return failure if at end of input. */
- if (yychar == YYEOF)
- {
- /* Pop the error token. */
- YYPOPSTACK;
- /* Pop the rest of the stack. */
- while (yyss < yyssp)
- {
- YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
- yydestruct (yystos[*yyssp], yyvsp);
- YYPOPSTACK;
- }
- YYABORT;
- }
-
- YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
- yydestruct (yytoken, &yylval);
- yychar = YYEMPTY;
-
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
}
/* Else will try to reuse lookahead token after shifting the error
token. */
- goto yyerrlab2;
+ goto yyerrlab1;
-/*----------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action. |
-`----------------------------------------------------*/
-yyerrlab1:
-
- /* Suppress GCC warning that yyerrlab1 is unused when no action
- invokes YYERROR. */
-#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__)
- __attribute__ ((__unused__))
-#endif
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
- goto yyerrlab2;
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
-/*---------------------------------------------------------------.
-| yyerrlab2 -- pop states until the error token can be shifted. |
-`---------------------------------------------------------------*/
-yyerrlab2:
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
yyerrstatus = 3; /* Each real token shifted decrements this. */
for (;;)
@@ -1774,22 +2255,20 @@ yyerrlab2:
if (yyssp == yyss)
YYABORT;
- YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
- yydestruct (yystos[yystate], yyvsp);
- yyvsp--;
- yystate = *--yyssp;
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
YY_STACK_PRINT (yyss, yyssp);
}
- if (yyn == YYFINAL)
- YYACCEPT;
-
- YYDPRINTF ((stderr, "Shifting error token, "));
-
*++yyvsp = yylval;
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
yystate = yyn;
goto yynewstate;
@@ -1808,22 +2287,40 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#ifndef yyoverflow
-/*----------------------------------------------.
-| yyoverflowlab -- parser overflow comes here. |
-`----------------------------------------------*/
-yyoverflowlab:
- yyerror ("parser stack overflow");
+#if !defined(yyoverflow) || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
yyresult = 2;
/* Fall through. */
#endif
yyreturn:
+ if (yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
#ifndef yyoverflow
if (yyss != yyssa)
YYSTACK_FREE (yyss);
#endif
- return yyresult;
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
}
diff --git a/tools/build/v2/engine/jamgram.h b/tools/build/v2/engine/jamgram.h
index 3cb7656417..97f117535d 100644
--- a/tools/build/v2/engine/jamgram.h
+++ b/tools/build/v2/engine/jamgram.h
@@ -1,27 +1,36 @@
-/* A Bison parser, made by GNU Bison 1.875. */
+/* A Bison parser, made by GNU Bison 2.4.3. */
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+ 2009, 2010 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
@@ -77,6 +86,7 @@
STRING = 303
};
#endif
+/* Tokens. */
#define _BANG_t 258
#define _BANG_EQUALS_t 259
#define _AMPER_t 260
@@ -127,14 +137,13 @@
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-
diff --git a/tools/build/v2/engine/jamgram.y b/tools/build/v2/engine/jamgram.y
index c26b1e1b6b..543f1561a4 100644
--- a/tools/build/v2/engine/jamgram.y
+++ b/tools/build/v2/engine/jamgram.y
@@ -100,34 +100,34 @@
#include "parse.h"
#include "scan.h"
#include "compile.h"
-#include "newstr.h"
+#include "object.h"
#include "rules.h"
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
@@ -325,9 +325,9 @@ arg : ARG
* This needs to be split cleanly out of 'rule'
*/
-func : arg lol
+func : ARG lol
{ $$.parse = prule( $1.string, $2.parse ); }
- | ON_t arg arg lol
+ | ON_t arg ARG lol
{ $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); }
| ON_t arg RETURN_t list
{ $$.parse = pon( $2.parse, $4.parse ); }
@@ -369,3 +369,5 @@ bindlist : /* empty */
| BIND_t list
{ $$.parse = $2.parse; }
;
+
+
diff --git a/tools/build/v2/engine/jamgram.yy b/tools/build/v2/engine/jamgram.yy
index 1524348710..8d20e3896e 100644
--- a/tools/build/v2/engine/jamgram.yy
+++ b/tools/build/v2/engine/jamgram.yy
@@ -56,34 +56,34 @@
#include "parse.h"
#include "scan.h"
#include "compile.h"
-#include "newstr.h"
+#include "object.h"
#include "rules.h"
# define YYMAXDEPTH 10000 /* for OSF and other less endowed yaccs */
-# define F0 (LIST *(*)(PARSE *, FRAME *))0
+# define F0 -1
# define P0 (PARSE *)0
-# define S0 (char *)0
-
-# define pappend( l,r ) parse_make( compile_append,l,r,P0,S0,S0,0 )
-# define peval( c,l,r ) parse_make( compile_eval,l,r,P0,S0,S0,c )
-# define pfor( s,l,r,x ) parse_make( compile_foreach,l,r,P0,s,S0,x )
-# define pif( l,r,t ) parse_make( compile_if,l,r,t,S0,S0,0 )
-# define pincl( l ) parse_make( compile_include,l,P0,P0,S0,S0,0 )
-# define plist( s ) parse_make( compile_list,P0,P0,P0,s,S0,0 )
-# define plocal( l,r,t ) parse_make( compile_local,l,r,t,S0,S0,0 )
-# define pmodule( l,r ) parse_make( compile_module,l,r,P0,S0,S0,0 )
-# define pclass( l,r ) parse_make( compile_class,l,r,P0,S0,S0,0 )
-# define pnull() parse_make( compile_null,P0,P0,P0,S0,S0,0 )
-# define pon( l,r ) parse_make( compile_on,l,r,P0,S0,S0,0 )
-# define prule( s,p ) parse_make( compile_rule,p,P0,P0,s,S0,0 )
-# define prules( l,r ) parse_make( compile_rules,l,r,P0,S0,S0,0 )
-# define pset( l,r,a ) parse_make( compile_set,l,r,P0,S0,S0,a )
-# define pset1( l,r,t,a ) parse_make( compile_settings,l,r,t,S0,S0,a )
-# define psetc( s,p,a,l ) parse_make( compile_setcomp,p,a,P0,s,S0,l )
-# define psete( s,l,s1,f ) parse_make( compile_setexec,l,P0,P0,s,s1,f )
-# define pswitch( l,r ) parse_make( compile_switch,l,r,P0,S0,S0,0 )
-# define pwhile( l,r ) parse_make( compile_while,l,r,P0,S0,S0,0 )
+# define S0 (OBJECT *)0
+
+# define pappend( l,r ) parse_make( PARSE_APPEND,l,r,P0,S0,S0,0 )
+# define peval( c,l,r ) parse_make( PARSE_EVAL,l,r,P0,S0,S0,c )
+# define pfor( s,l,r,x ) parse_make( PARSE_FOREACH,l,r,P0,s,S0,x )
+# define pif( l,r,t ) parse_make( PARSE_IF,l,r,t,S0,S0,0 )
+# define pincl( l ) parse_make( PARSE_INCLUDE,l,P0,P0,S0,S0,0 )
+# define plist( s ) parse_make( PARSE_LIST,P0,P0,P0,s,S0,0 )
+# define plocal( l,r,t ) parse_make( PARSE_LOCAL,l,r,t,S0,S0,0 )
+# define pmodule( l,r ) parse_make( PARSE_MODULE,l,r,P0,S0,S0,0 )
+# define pclass( l,r ) parse_make( PARSE_CLASS,l,r,P0,S0,S0,0 )
+# define pnull() parse_make( PARSE_NULL,P0,P0,P0,S0,S0,0 )
+# define pon( l,r ) parse_make( PARSE_ON,l,r,P0,S0,S0,0 )
+# define prule( s,p ) parse_make( PARSE_RULE,p,P0,P0,s,S0,0 )
+# define prules( l,r ) parse_make( PARSE_RULES,l,r,P0,S0,S0,0 )
+# define pset( l,r,a ) parse_make( PARSE_SET,l,r,P0,S0,S0,a )
+# define pset1( l,r,t,a ) parse_make( PARSE_SETTINGS,l,r,t,S0,S0,a )
+# define psetc( s,p,a,l ) parse_make( PARSE_SETCOMP,p,a,P0,s,S0,l )
+# define psete( s,l,s1,f ) parse_make( PARSE_SETEXEC,l,P0,P0,s,s1,f )
+# define pswitch( l,r ) parse_make( PARSE_SWITCH,l,r,P0,S0,S0,0 )
+# define pwhile( l,r ) parse_make( PARSE_WHILE,l,r,P0,S0,S0,0 )
# define pnode( l,r ) parse_make( F0,l,r,P0,S0,S0,0 )
# define psnode( s,l ) parse_make( F0,l,P0,P0,s,S0,0 )
@@ -281,9 +281,9 @@ arg : ARG
* This needs to be split cleanly out of 'rule'
*/
-func : arg lol
+func : ARG lol
{ $$.parse = prule( $1.string, $2.parse ); }
- | `on` arg arg lol
+ | `on` arg ARG lol
{ $$.parse = pon( $2.parse, prule( $3.string, $4.parse ) ); }
| `on` arg `return` list
{ $$.parse = pon( $2.parse, $4.parse ); }
diff --git a/tools/build/v2/engine/lists.c b/tools/build/v2/engine/lists.c
index ebabb63e90..c93fd7c090 100644
--- a/tools/build/v2/engine/lists.c
+++ b/tools/build/v2/engine/lists.c
@@ -5,27 +5,65 @@
*/
# include "jam.h"
-# include "newstr.h"
+# include "object.h"
# include "lists.h"
+# include "assert.h"
/*
- * lists.c - maintain lists of strings
- *
- * This implementation essentially uses a singly linked list, but
- * guarantees that the head element of every list has a valid pointer
- * to the tail of the list, so the new elements can efficiently and
- * properly be appended to the end of a list.
- *
- * To avoid massive allocation, list_free() just tacks the whole freed
- * chain onto freelist and list_new() looks on freelist first for an
- * available list struct. list_free() does not free the strings in the
- * chain: it lazily lets list_new() do so.
+ * lists.c - maintain lists of objects
*
* 08/23/94 (seiwald) - new list_append()
* 09/07/00 (seiwald) - documented lol_*() functions
*/
-static LIST *freelist = 0; /* junkpile for list_free() */
+struct freelist_node { struct freelist_node *next; };
+
+static struct freelist_node *freelist[32]; /* junkpile for list_free() */
+
+static unsigned get_bucket( unsigned size )
+{
+ unsigned bucket = 0;
+ while ( size > ( 1u << bucket ) ) ++bucket;
+ return bucket;
+}
+
+static LIST * list_alloc( unsigned size )
+{
+ unsigned 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 * ) );
+ }
+}
+
+static void list_dealloc( LIST * l )
+{
+ unsigned size = list_length( l );
+ unsigned bucket;
+ struct freelist_node * node = (struct freelist_node *)l;
+
+ if ( size == 0 ) return;
+
+ bucket = get_bucket( size );;
+
+#ifdef BJAM_NO_MEM_CACHE
+
+ BJAM_FREE( node );
+
+#else
+
+ node->next = freelist[ bucket ];
+ freelist[ bucket ] = node;
+
+#endif
+
+}
/*
* list_append() - append a list onto another one, returning total
@@ -33,60 +71,104 @@ static LIST *freelist = 0; /* junkpile for list_free() */
LIST * list_append( LIST * l, LIST * nl )
{
- if ( !nl )
+ if ( list_empty( nl ) )
{
/* Just return l */
}
- else if ( !l )
+ else if ( list_empty( l ) )
{
l = nl;
}
else
{
- /* Graft two non-empty lists. */
- l->tail->next = nl;
- l->tail = nl->tail;
+ int l_size = list_length( l );
+ int nl_size = list_length( nl );
+ int size = l_size + nl_size;
+ unsigned bucket;
+ int i;
+
+ bucket = get_bucket( size );
+ /* Do we need to reallocate? */
+ if ( l_size <= ( 1u << (bucket - 1) ) )
+ {
+ LIST * result = list_alloc( size );
+ 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 * ) );
+ list_dealloc( nl );
+ return l;
}
return l;
}
+LISTITER list_begin( LIST * l )
+{
+ if ( l )
+ return (LISTITER)( (char *)l + sizeof(LIST) );
+ else
+ return 0;
+}
+
+LISTITER list_end( LIST * l )
+{
+ if ( l )
+ return list_begin( l ) + l->impl.size;
+ else
+ return 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 * ) );
+ }
+
+ head->impl.size = 1;
+ list_begin( head )[ 0 ] = value;
+
+ return head;
+}
+
/*
- * list_new() - tack a string onto the end of a list of strings
+ * list_push_back() - tack a string onto the end of a list of strings
*/
-LIST * list_new( LIST * head, char * string )
+LIST * list_push_back( LIST * head, OBJECT * value )
{
- LIST * l;
+ unsigned int size = list_length( head );
+ unsigned int i;
if ( DEBUG_LISTS )
- printf( "list > %s <\n", string );
+ printf( "list > %s <\n", object_str( value ) );
- /* Get list struct from freelist, if one available. */
- /* Otherwise allocate. */
- /* If from freelist, must free string first */
-
- if ( freelist )
+ /* If the size is a power of 2, reallocate. */
+ if ( size == 0 )
{
- l = freelist;
- freestr( l->string );
- freelist = freelist->next;
+ head = list_alloc( 1 );
}
- else
+ else if ( ( ( size - 1 ) & size ) == 0 )
{
- l = (LIST *)BJAM_MALLOC( sizeof( LIST ) );
+ LIST * l = list_alloc( size + 1 );
+ memcpy( l, head, sizeof( LIST ) + size * sizeof( OBJECT * ) );
+ list_dealloc( head );
+ head = l;
}
- /* If first on chain, head points here. */
- /* If adding to chain, tack us on. */
- /* Tail must point to this new, last element. */
-
- if ( !head ) head = l;
- else head->tail->next = l;
- head->tail = l;
- l->next = 0;
-
- l->string = string;
+ list_begin( head )[ size ] = value;
+ head->impl.size = size + 1;
return head;
}
@@ -96,11 +178,42 @@ LIST * list_new( LIST * head, char * string )
* list_copy() - copy a whole list of strings (nl) onto end of another (l).
*/
-LIST * list_copy( LIST * l, LIST * nl )
+LIST * list_copy( LIST * l )
{
- for ( ; nl; nl = list_next( nl ) )
- l = list_new( l, copystr( nl->string ) );
- return l;
+ int size = list_length( l );
+ int i;
+ LIST * result;
+
+ if ( size == 0 ) return L0;
+
+ 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 )
+{
+ if ( first == last )
+ {
+ return L0;
+ }
+ else
+ {
+ int size = last - first;
+ LIST * result = list_alloc( size );
+ LISTITER dest = list_begin( result );
+ result->impl.size = size;
+ for ( ; first != last; ++first, ++dest )
+ {
+ *dest = object_copy( *first );
+ }
+ return result;
+ }
}
@@ -110,19 +223,19 @@ LIST * list_copy( LIST * l, LIST * nl )
LIST * list_sublist( LIST * l, int start, int count )
{
- LIST * nl = 0;
- for ( ; l && start--; l = list_next( l ) );
- for ( ; l && count--; l = list_next( l ) )
- nl = list_new( nl, copystr( l->string ) );
- return nl;
+ int end = start + count;
+ int size = list_length( l );
+ if ( start >= size ) return L0;
+ if ( end > size ) end = size;
+ return list_copy_range( l, list_begin( l ) + start, list_begin( l ) + end );
}
static int str_ptr_compare( void const * va, void const * vb )
{
- char * a = *( (char * *)va );
- char * b = *( (char * *)vb );
- return strcmp(a, b);
+ OBJECT * a = *( (OBJECT * *)va );
+ OBJECT * b = *( (OBJECT * *)vb );
+ return strcmp(object_str(a), object_str(b));
}
@@ -130,29 +243,15 @@ LIST * list_sort( LIST * l )
{
int len;
int ii;
- char * * strings;
- LIST * listp;
- LIST * result = 0;
+ LIST * result;
if ( !l )
return L0;
len = list_length( l );
- strings = (char * *)BJAM_MALLOC( len * sizeof(char*) );
-
- listp = l;
- for ( ii = 0; ii < len; ++ii )
- {
- strings[ ii ] = listp->string;
- listp = listp->next;
- }
-
- qsort( strings, len, sizeof( char * ), str_ptr_compare );
+ result = list_copy( l );
- for ( ii = 0; ii < len; ++ii )
- result = list_append( result, list_new( 0, strings[ ii ] ) );
-
- BJAM_FREE( strings );
+ qsort( list_begin( result ), len, sizeof( OBJECT * ), str_ptr_compare );
return result;
}
@@ -164,11 +263,14 @@ LIST * list_sort( LIST * l )
void list_free( LIST * head )
{
- /* Just tack onto freelist. */
- if ( head )
+ if ( !list_empty( head ) )
{
- head->tail->next = freelist;
- freelist = head;
+ LISTITER iter = list_begin( head ), end = list_end( head );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ object_free( list_item( iter ) );
+ }
+ list_dealloc( head );
}
}
@@ -179,17 +281,79 @@ void list_free( LIST * head )
LIST * list_pop_front( LIST * l )
{
- LIST * result = l->next;
- if ( result )
+ unsigned size = list_length( l );
+ assert( size != 0 );
+ --size;
+ object_free( list_front( l ) );
+
+ if ( size == 0 )
{
- result->tail = l->tail;
- l->next = L0;
- l->tail = l;
+ list_dealloc( l );
+ return L0;
+ }
+ else if ( ( ( size - 1 ) & size ) == 0 )
+ {
+ LIST * nl = list_alloc( size );
+ nl->impl.size = size;
+ 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;
+ }
+}
+
+LIST * list_reverse( LIST * l )
+{
+ int size = list_length( l );
+ if ( size == 0 ) return L0;
+ else
+ {
+ LIST * 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 ] );
+ }
+ return result;
}
- list_free( l );
- return result;
}
+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 );
+
+ 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 ) ) : "";
+
+ status = strcmp( st, ss );
+
+ t_it = t_it != t_end ? list_next( t_it ) : t_it;
+ s_it = s_it != s_end ? list_next( s_it ) : s_it;
+ }
+
+ return status;
+}
+
+int list_is_sublist( LIST * sub, LIST * l )
+{
+ LISTITER iter = list_begin( sub ), end = list_end( sub );
+ for ( ; iter != end; iter = list_next( iter ) )
+ {
+ if ( !list_in( l, list_item( iter ) ) )
+ return 0;
+ }
+ return 1;
+}
/*
* list_print() - print a list of strings to stdout
@@ -197,12 +361,14 @@ LIST * list_pop_front( LIST * l )
void list_print( LIST * l )
{
- LIST * p = 0;
- for ( ; l; p = l, l = list_next( l ) )
- if ( p )
- printf( "%s ", p->string );
- if ( p )
- printf( "%s", p->string );
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ if ( iter != end )
+ {
+ printf( "%s", object_str( list_item( iter ) ) );
+ iter = list_next( iter );
+ for ( ; iter != end; iter = list_next( iter ) )
+ printf( " %s", object_str( list_item( iter ) ) );
+ }
}
@@ -212,16 +378,18 @@ void list_print( LIST * l )
int list_length( LIST * l )
{
- int n = 0;
- for ( ; l; l = list_next( l ), ++n );
- return n;
+ if ( l )
+ return l->impl.size;
+ else
+ return 0;
}
-int list_in( LIST * l, char * value )
+int list_in( LIST * l, OBJECT * value )
{
- for ( ; l; l = l->next )
- if ( strcmp( l->string, value ) == 0 )
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ if ( object_equal( list_item( iter ), value ) )
return 1;
return 0;
}
@@ -229,20 +397,38 @@ int list_in( LIST * l, char * value )
LIST * list_unique( LIST * sorted_list )
{
- LIST * result = 0;
- LIST * last_added = 0;
+ LIST * result = L0;
+ OBJECT * last_added = 0;
- for ( ; sorted_list; sorted_list = sorted_list->next )
+ LISTITER iter = list_begin( sorted_list ), end = list_end( sorted_list );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- if ( !last_added || strcmp( sorted_list->string, last_added->string ) != 0 )
+ if ( !last_added || !object_equal( list_item( iter ), last_added ) )
{
- result = list_new( result, sorted_list->string );
- last_added = sorted_list;
+ result = list_push_back( result, object_copy( list_item( iter ) ) );
+ last_added = list_item( iter );
}
}
return result;
}
+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; )
+ {
+ tmp = l;
+ l = l->next;
+ BJAM_FREE( tmp );
+ }
+ }
+}
+
/*
* lol_init() - initialize a LOL (list of lists).
@@ -284,7 +470,7 @@ void lol_free( LOL * lol )
LIST * lol_get( LOL * lol, int i )
{
- return i < lol->count ? lol->list[ i ] : 0;
+ return i < lol->count ? lol->list[ i ] : L0;
}
@@ -309,10 +495,11 @@ void lol_print( LOL * lol )
PyObject *list_to_python(LIST *l)
{
PyObject *result = PyList_New(0);
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for (; l; l = l->next)
+ for (; iter != end; iter = list_next( iter ) )
{
- PyObject* s = PyString_FromString(l->string);
+ PyObject* s = PyString_FromString(object_str(list_item(iter)));
PyList_Append(result, s);
Py_DECREF(s);
}
@@ -322,14 +509,14 @@ PyObject *list_to_python(LIST *l)
LIST *list_from_python(PyObject *l)
{
- LIST * result = 0;
+ 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_new (result, newstr (PyString_AsString(v)));
+ result = list_push_back(result, object_new (PyString_AsString(v)));
Py_DECREF(v);
}
diff --git a/tools/build/v2/engine/lists.h b/tools/build/v2/engine/lists.h
index 1dc598274d..bc97261e57 100644
--- a/tools/build/v2/engine/lists.h
+++ b/tools/build/v2/engine/lists.h
@@ -13,23 +13,23 @@
/*
* lists.h - the LIST structure and routines to manipulate them
*
- * The whole of jam relies on lists of strings as a datatype. This
- * module, in conjunction with newstr.c, handles these relatively
+ * 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:
*
- * LIST - list of strings
+ * LIST - list of OBJECTs
* LOL - list of LISTs
*
* External routines:
*
* list_append() - append a list onto another one, returning total
- * list_new() - tack a string onto the end of a list of strings
- * list_copy() - copy a whole list of strings
- * list_sublist() - copy a subset of a list of strings
- * list_free() - free a list of strings
- * list_print() - print a list of strings to stdout
+ * list_new() - tack an object onto the end of a list of objects
+ * list_copy() - copy a whole list of objects
+ * list_sublist() - copy a subset of a list of objects
+ * list_free() - free a list of objects
+ * list_print() - print a list of objects to stdout
* list_length() - return the number of items in the list
*
* lol_init() - initialize a LOL (list of lists)
@@ -45,6 +45,8 @@
#ifndef LISTS_DWA20011022_H
# define LISTS_DWA20011022_H
+#include "object.h"
+
#ifdef HAVE_PYTHON
#include <Python.h>
#endif
@@ -56,11 +58,14 @@
typedef struct _list LIST;
struct _list {
- LIST *next;
- LIST *tail; /* only valid in head node */
- char *string; /* private copy */
+ union {
+ int size;
+ OBJECT *align;
+ } impl;
};
+typedef OBJECT * * LISTITER;
+
/*
* LOL - list of LISTs
*/
@@ -74,19 +79,30 @@ struct _lol {
LIST *list[ LOL_MAX ];
};
+LIST * list_new( OBJECT * value );
LIST * list_append( LIST *l, LIST *nl );
-LIST * list_copy( 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_new( LIST *head, char *string );
+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, char* value);
-
-# define list_next( l ) ((l)->next)
+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();
+
+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)
@@ -95,7 +111,7 @@ 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, char** elements );
+void lol_build( LOL* lol, const char** elements );
#ifdef HAVE_PYTHON
diff --git a/tools/build/v2/engine/make.c b/tools/build/v2/engine/make.c
index c871f0be2d..96416cbd52 100644
--- a/tools/build/v2/engine/make.c
+++ b/tools/build/v2/engine/make.c
@@ -58,7 +58,7 @@
#endif
#include "search.h"
-#include "newstr.h"
+#include "object.h"
#include "make.h"
#include "headers.h"
#include "command.h"
@@ -106,9 +106,8 @@ static const char * target_bind[] =
* make() - make a target, given its name.
*/
-int make( int n_targets, char const * * targets, int anyhow )
+int make( LIST * targets, int anyhow )
{
- int i;
COUNTS counts[ 1 ];
int status = 0; /* 1 if anything fails */
@@ -124,16 +123,24 @@ int make( int n_targets, char const * * targets, int anyhow )
bind_explicitly_located_targets();
{
+ LISTITER iter, end;
PROFILE_ENTER( MAKE_MAKE0 );
- for ( i = 0; i < n_targets; ++i )
- make0( bindtarget( targets[ i ] ), 0, 0, counts, anyhow );
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ {
+ TARGET * t = bindtarget( list_item( iter ) );
+ if ( t->fate == T_FATE_INIT )
+ make0( t, 0, 0, counts, anyhow );
+ }
PROFILE_EXIT( MAKE_MAKE0 );
}
#ifdef OPT_GRAPH_DEBUG_EXT
if ( DEBUG_GRAPH )
- for ( i = 0; i < n_targets; ++i )
- dependGraphOutput( bindtarget( targets[ i ] ), 0 );
+ {
+ LISTITER iter, end;
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ dependGraphOutput( bindtarget( list_item( iter ) ), 0 );
+ }
#endif
if ( DEBUG_MAKE )
@@ -155,16 +162,13 @@ int make( int n_targets, char const * * targets, int anyhow )
counts->cantmake > 1 ? "s" : "" );
}
-#ifdef OPT_HEADER_CACHE_EXT
- hcache_done();
-#endif
-
status = counts->cantfind || counts->cantmake;
{
+ LISTITER iter, end;
PROFILE_ENTER( MAKE_MAKE1 );
- for ( i = 0; i < n_targets; ++i )
- status |= make1( bindtarget( targets[ i ] ) );
+ for ( iter = list_begin( targets ), end = list_end( targets ); iter != end; iter = list_next( iter ) )
+ status |= make1( bindtarget( list_item( iter ) ) );
PROFILE_EXIT( MAKE_MAKE1 );
}
@@ -195,7 +199,7 @@ static void update_dependants( TARGET * t )
if ( DEBUG_FATE )
{
printf( "fate change %s from %s to %s (as dependant of %s)\n",
- p->name, target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], t->name );
+ object_str( p->name ), target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], object_str( t->name ) );
}
/* If we are done visiting it, go back and make sure its dependants
@@ -224,7 +228,7 @@ static void force_rebuilds( TARGET * t )
{
if ( DEBUG_FATE )
printf( "fate change %s from %s to %s (by rebuild)\n",
- r->name, target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] );
+ object_str( r->name ), target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] );
/* Force rebuild it. */
r->fate = T_FATE_REBUILD;
@@ -266,14 +270,14 @@ void make0
#endif
if ( DEBUG_MAKEPROG )
- printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+ printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
/*
* Step 1: initialize
*/
if ( DEBUG_MAKEPROG )
- printf( "make\t--\t%s%s\n", spaces( depth ), t->name );
+ printf( "make\t--\t%s%s\n", spaces( depth ), object_str( t->name ) );
t->fate = T_FATE_MAKING;
@@ -284,12 +288,13 @@ void make0
/* Step 2a: set "on target" variables. */
s = copysettings( t->settings );
- pushsettings( s );
+ pushsettings( root_module(), s );
/* Step 2b: find and timestamp the target file (if it is a file). */
if ( ( t->binding == T_BIND_UNBOUND ) && !( t->flags & T_FLAG_NOTFILE ) )
{
- char * another_target;
+ OBJECT * another_target;
+ object_free( t->boundname );
t->boundname = search( t->name, &t->time, &another_target,
t->flags & T_FLAG_ISFILE );
/* If it was detected that this target refers to an already existing and
@@ -317,10 +322,10 @@ void make0
#ifdef OPT_SEMAPHORE
{
- LIST * var = var_get( "JAM_SEMAPHORE" );
- if ( var )
+ LIST * var = var_get( root_module(), constant_JAM_SEMAPHORE );
+ if ( !list_empty( var ) )
{
- TARGET * semaphore = bindtarget( var->string );
+ TARGET * semaphore = bindtarget( list_front( var ) );
semaphore->progress = T_MAKE_SEMAPHORE;
t->semaphore = semaphore;
}
@@ -332,7 +337,7 @@ void make0
headers( t );
/* Step 2d: reset "on target" variables. */
- popsettings( s );
+ popsettings( root_module(), s );
freesettings( s );
/*
@@ -341,9 +346,9 @@ void make0
if ( DEBUG_BIND )
{
- if ( strcmp( t->name, t->boundname ) )
+ if ( ! object_equal( t->name, t->boundname ) )
printf( "bind\t--\t%s%s: %s\n",
- spaces( depth ), t->name, t->boundname );
+ spaces( depth ), object_str( t->name ), object_str( t->boundname ) );
switch ( t->binding )
{
@@ -351,12 +356,12 @@ void make0
case T_BIND_MISSING:
case T_BIND_PARENTS:
printf( "time\t--\t%s%s: %s\n",
- spaces( depth ), t->name, target_bind[ (int) t->binding ] );
+ 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 ), t->name, ctime( &t->time ) );
+ spaces( depth ), object_str( t->name ), ctime( &t->time ) );
break;
}
}
@@ -376,7 +381,7 @@ void make0
if ( c->target->fate == T_FATE_INIT )
make0( c->target, ptime, depth + 1, counts, anyhow );
else if ( c->target->fate == T_FATE_MAKING && !internal )
- printf( "warning: %s depends on itself\n", c->target->name );
+ printf( "warning: %s depends on itself\n", object_str( c->target->name ) );
}
/* Step 3b: recursively make0() internal includes node. */
@@ -420,8 +425,8 @@ void make0
if ( DEBUG_FATE )
if ( fate < c->target->fate )
printf( "fate change %s from %s to %s by dependency %s\n",
- t->name, target_fate[(int) fate], target_fate[(int) c->target->fate],
- c->target->name );
+ object_str( t->name ), target_fate[(int) fate], target_fate[(int) c->target->fate],
+ object_str( c->target->name ) );
#endif
}
@@ -445,8 +450,8 @@ void make0
#ifdef OPT_GRAPH_DEBUG_EXT
if ( DEBUG_FATE )
if ( fate != T_FATE_STABLE )
- printf( "fate change %s back to stable, NOUPDATE.\n", t->name
- );
+ printf( "fate change %s back to stable, NOUPDATE.\n",
+ object_str( t->name ) );
#endif
last = 0;
@@ -541,10 +546,10 @@ void make0
if ( DEBUG_FATE && ( fate != savedFate ) )
{
if ( savedFate == T_FATE_STABLE )
- printf( "fate change %s set to %s%s\n", t->name,
+ printf( "fate change %s set to %s%s\n", object_str( t->name ),
target_fate[ fate ], oldTimeStamp ? " (by timestamp)" : "" );
else
- printf( "fate change %s from %s to %s%s\n", t->name,
+ printf( "fate change %s from %s to %s%s\n", object_str( t->name ),
target_fate[ savedFate ], target_fate[ fate ],
oldTimeStamp ? " (by timestamp)" : "" );
}
@@ -564,13 +569,13 @@ void make0
if ( DEBUG_FATE )
printf( "fate change %s to STABLE from %s, "
"no actions, no dependencies and do not care\n",
- t->name, target_fate[ fate ] );
+ object_str( t->name ), target_fate[ fate ] );
#endif
fate = T_FATE_STABLE;
}
else
{
- printf( "don't know how to make %s\n", t->name );
+ printf( "don't know how to make %s\n", object_str( t->name ) );
fate = T_FATE_CANTFIND;
}
}
@@ -637,7 +642,7 @@ void make0
if ( DEBUG_MAKEPROG )
printf( "made%s\t%s\t%s%s\n", flag, target_fate[ (int) t->fate ],
- spaces( depth ), t->name );
+ spaces( depth ), object_str( t->name ) );
}
@@ -648,10 +653,10 @@ static const char * target_name( TARGET * t )
static char buf[ 1000 ];
if ( t->flags & T_FLAG_INTERNAL )
{
- sprintf( buf, "%s (internal node)", t->name );
+ sprintf( buf, "%s (internal node)", object_str( t->name ) );
return buf;
}
- return t->name;
+ return object_str( t->name );
}
@@ -681,8 +686,8 @@ static void dependGraphOutput( TARGET * t, int depth )
break;
}
- if ( strcmp( t->name, t->boundname ) )
- printf( " %s Loc: %s\n", spaces( depth ), t->boundname );
+ if ( ! object_equal( t->name, t->boundname ) )
+ printf( " %s Loc: %s\n", spaces( depth ), object_str( t->boundname ) );
switch ( t->fate )
{
@@ -792,12 +797,12 @@ static TARGETS * make0sort( TARGETS * chain )
}
-static LIST * targets_to_update_ = 0;
+static LIST * targets_to_update_ = L0;
-void mark_target_for_updating( char * target )
+void mark_target_for_updating( OBJECT * target )
{
- targets_to_update_ = list_new( targets_to_update_, target );
+ targets_to_update_ = list_push_back( targets_to_update_, object_copy( target ) );
}
@@ -810,5 +815,5 @@ LIST * targets_to_update()
void clear_targets_to_update()
{
list_free( targets_to_update_ );
- targets_to_update_ = 0;
+ targets_to_update_ = L0;
}
diff --git a/tools/build/v2/engine/make.h b/tools/build/v2/engine/make.h
index b372263e19..e0c7906583 100644
--- a/tools/build/v2/engine/make.h
+++ b/tools/build/v2/engine/make.h
@@ -8,10 +8,14 @@
* make.h - bring a target up to date, once rules are in place
*/
+#ifndef MAKE_SW20111118_H
+#define MAKE_SW20111118_H
+
#include "lists.h"
+#include "object.h"
-int make( int n_targets, const char **targets, int anyhow );
-int make1( TARGET *t );
+int make( LIST * targets, int anyhow );
+int make1( TARGET * t );
typedef struct {
int temp;
@@ -30,12 +34,14 @@ void make0( TARGET *t, TARGET *p, int depth,
/*
* Specifies that the target should be updated.
*/
-void mark_target_for_updating(char *target);
+void mark_target_for_updating( OBJECT * target );
/*
* Returns the list of all the target previously passed to 'mark_target_for_updating'.
*/
-LIST *targets_to_update();
+LIST * targets_to_update();
/*
* Cleasr/unmarks all targets that are currently marked for update.
*/
void clear_targets_to_update();
+
+#endif
diff --git a/tools/build/v2/engine/make1.c b/tools/build/v2/engine/make1.c
index 8001f33390..47132419a8 100644
--- a/tools/build/v2/engine/make1.c
+++ b/tools/build/v2/engine/make1.c
@@ -57,7 +57,7 @@
#include "headers.h"
#include "search.h"
-#include "newstr.h"
+#include "object.h"
#include "make.h"
#include "command.h"
#include "execcmd.h"
@@ -72,7 +72,7 @@
static CMD * make1cmds ( TARGET * );
static LIST * make1list ( LIST *, TARGETS *, int flags );
-static SETTINGS * make1settings( LIST * vars );
+static SETTINGS * make1settings( struct module_t * module, LIST * vars );
static void make1bind ( TARGET * );
/* Ugly static - it is too hard to carry it through the callbacks. */
@@ -107,7 +107,7 @@ 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 *, char *, char * );
+static void make_closure( void * closure, int status, timing_info *, const char *, const char * );
typedef struct _stack
{
@@ -281,6 +281,15 @@ static void make1a( state * pState )
++pState->parent->asynccnt;
}
+ /*
+ * If the target has been previously updated with -n in
+ * effect, and we're ignoring -n, update it for real.
+ */
+ if ( !globs.noexec && pState->t->progress == T_MAKE_NOEXEC_DONE )
+ {
+ pState->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.
*/
@@ -350,10 +359,10 @@ static void make1atail( state * pState )
static void make1b( state * pState )
{
- TARGET * t = pState->t;
- TARGETS * c;
- TARGET * failed = 0;
- char * failed_name = "dependencies";
+ TARGET * t = pState->t;
+ TARGETS * c;
+ TARGET * failed = 0;
+ const char * failed_name = "dependencies";
/* If any dependencies are still outstanding, wait until they call make1b()
* to signal their completion.
@@ -376,7 +385,7 @@ static void make1b( state * pState )
if ( DEBUG_EXECCMD )
printf( "SEM: %s is busy, delaying launch of %s\n",
- t->semaphore->name, t->name );
+ object_str( t->semaphore->name ), object_str( t->name ) );
pop_state( &state_stack );
return;
}
@@ -384,13 +393,21 @@ static void make1b( state * pState )
/* Now ready to build target 't', if dependencies built OK. */
- /* Collect status from dependencies. */
- for ( c = t->depends; c; c = c->next )
- if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
- {
- failed = c->target;
- pState->t->status = c->target->status;
- }
+ /* 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.
+ */
+ if ( !globs.noexec )
+ {
+ for ( c = t->depends; c; c = c->next )
+ if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) )
+ {
+ failed = c->target;
+ pState->t->status = c->target->status;
+ }
+ }
/* If an internal header node failed to build, we want to output the target
* that it failed on.
*/
@@ -398,7 +415,7 @@ static void make1b( state * pState )
{
failed_name = failed->flags & T_FLAG_INTERNAL
? failed->failed
- : failed->name;
+ : object_str( failed->name );
}
t->failed = failed_name;
@@ -410,11 +427,11 @@ static void make1b( state * pState )
++counts->skipped;
if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
{
- if ( !unlink( pState->t->boundname ) )
- printf( "...removing outdated %s\n", pState->t->boundname );
+ if ( !unlink( object_str( pState->t->boundname ) ) )
+ printf( "...removing outdated %s\n", object_str( pState->t->boundname ) );
}
else
- printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name );
+ printf( "...skipped %s for lack of %s...\n", object_str( pState->t->name ), failed_name );
}
if ( pState->t->status == EXEC_CMD_OK )
@@ -436,7 +453,7 @@ static void make1b( state * pState )
case T_FATE_ISTMP:
if ( DEBUG_MAKE )
- printf( "...using %s...\n", pState->t->name );
+ printf( "...using %s...\n", object_str( pState->t->name ) );
break;
case T_FATE_TOUCHED:
@@ -467,7 +484,7 @@ static void make1b( state * pState )
/* All possible fates should have been accounted for by now. */
default:
- printf( "ERROR: %s has bad fate %d", pState->t->name,
+ printf( "ERROR: %s has bad fate %d", object_str( pState->t->name ),
pState->t->fate );
abort();
}
@@ -484,8 +501,8 @@ static void make1b( state * pState )
{
++pState->t->semaphore->asynccnt;
if ( DEBUG_EXECCMD )
- printf( "SEM: %s now used by %s\n", pState->t->semaphore->name,
- pState->t->name );
+ printf( "SEM: %s now used by %s\n", object_str( pState->t->semaphore->name ),
+ object_str( pState->t->name ) );
}
#endif
@@ -508,16 +525,16 @@ static void make1c( state * pState )
if ( cmd && ( pState->t->status == EXEC_CMD_OK ) )
{
- char * rule_name = 0;
- char * target = 0;
+ const char * rule_name = 0;
+ const char * target = 0;
if ( DEBUG_MAKEQ ||
( !( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE ) )
{
- rule_name = cmd->rule->name;
- target = lol_get( &cmd->args, 0 )->string;
+ 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, "", "", EXIT_OK );
+ out_action( rule_name, target, cmd->buf->value, "", "", EXIT_OK );
}
if ( globs.noexec )
@@ -529,7 +546,7 @@ static void make1c( state * pState )
{
/* Pop state first because exec_cmd() could push state. */
pop_state( &state_stack );
- exec_cmd( cmd->buf, make_closure, pState->t, cmd->shell, rule_name,
+ exec_cmd( cmd->buf->value, make_closure, pState->t, cmd->shell, rule_name,
target );
}
}
@@ -560,13 +577,17 @@ static void make1c( state * pState )
TARGET * t = pState->t;
TARGET * additional_includes = NULL;
- t->progress = T_MAKE_DONE;
+ if ( globs.noexec )
+ t->progress = T_MAKE_NOEXEC_DONE;
+ else
+ t->progress = 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 )
{
+ TARGET * saved_includes;
TARGET * target_to_rescan = t;
SETTINGS * s;
@@ -576,16 +597,21 @@ static void make1c( state * pState )
target_to_rescan = t->original_target;
/* Clean current includes. */
+ saved_includes = target_to_rescan->includes;
target_to_rescan->includes = 0;
s = copysettings( target_to_rescan->settings );
- pushsettings( s );
+ pushsettings( root_module(), s );
headers( target_to_rescan );
- popsettings( s );
+ popsettings( root_module(), s );
freesettings( s );
if ( target_to_rescan->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
@@ -604,6 +630,10 @@ static void make1c( state * pState )
/* Will be processed below. */
additional_includes = target_to_rescan->includes;
}
+ else
+ {
+ target_to_rescan->includes = saved_includes;
+ }
}
if ( additional_includes )
@@ -621,7 +651,7 @@ static void make1c( state * pState )
--t->semaphore->asynccnt;
if ( DEBUG_EXECCMD )
- printf( "SEM: %s is now free\n", 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
@@ -635,7 +665,7 @@ static void make1c( state * pState )
t->semaphore->parents = first->next;
if ( DEBUG_EXECCMD )
- printf( "SEM: placing %s on stack\n", first->target->name );
+ 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 );
}
@@ -662,11 +692,11 @@ static void call_timing_rule( TARGET * target, timing_info * time )
{
LIST * timing_rule;
- pushsettings( target->settings );
- timing_rule = var_get( "__TIMING_RULE__" );
- popsettings( target->settings );
+ pushsettings( root_module(), target->settings );
+ timing_rule = var_get( root_module(), constant_TIMING_RULE );
+ popsettings( root_module(), target->settings );
- if ( timing_rule )
+ if ( !list_empty( timing_rule ) )
{
/* rule timing-rule ( args * : target : start end user system ) */
@@ -675,20 +705,20 @@ static void call_timing_rule( TARGET * target, timing_info * time )
frame_init( frame );
/* args * :: $(__TIMING_RULE__[2-]) */
- lol_add( frame->args, list_copy( L0, timing_rule->next ) );
+ 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( L0, target->name ) );
+ lol_add( frame->args, list_new( object_copy( target->name ) ) );
/* start end user system :: info about the action command */
- lol_add( frame->args, list_new( list_new( list_new( list_new( L0,
+ 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_double( time->system ) ) );
/* Call the rule. */
- evaluate_rule( timing_rule->string, frame );
+ evaluate_rule( list_front( timing_rule ), frame );
/* Clean up. */
frame_free( frame );
@@ -707,17 +737,17 @@ static void call_action_rule
TARGET * target,
int status,
timing_info * time,
- char * executed_command,
- char * command_output
+ const char * executed_command,
+ const char * command_output
)
{
- LIST * action_rule;
+ LIST * action_rule;
- pushsettings( target->settings );
- action_rule = var_get( "__ACTION_RULE__" );
- popsettings( target->settings );
+ pushsettings( root_module(), target->settings );
+ action_rule = var_get( root_module(), constant_ACTION_RULE );
+ popsettings( root_module(), target->settings );
- if ( action_rule )
+ if ( !list_empty( action_rule ) )
{
/* rule action-rule (
args * :
@@ -730,15 +760,15 @@ static void call_action_rule
frame_init( frame );
/* args * :: $(__ACTION_RULE__[2-]) */
- lol_add( frame->args, list_copy( L0, action_rule->next ) );
+ 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( L0, target->name ) );
+ lol_add( frame->args, list_new( object_copy( target->name ) ) );
/* command status start end user system :: info about the action command */
lol_add( frame->args,
- list_new( list_new( list_new( list_new( list_new( list_new( L0,
- newstr( executed_command ) ),
+ 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 ) ),
@@ -747,12 +777,12 @@ static void call_action_rule
/* output ? :: the output of the action command */
if ( command_output )
- lol_add( frame->args, list_new( L0, newstr( command_output ) ) );
+ lol_add( frame->args, list_new( object_new( command_output ) ) );
else
lol_add( frame->args, L0 );
/* Call the rule. */
- evaluate_rule( action_rule->string, frame );
+ evaluate_rule( list_front( action_rule ), frame );
/* Clean up. */
frame_free( frame );
@@ -770,8 +800,8 @@ static void make_closure
void * closure,
int status,
timing_info * time,
- char * executed_command,
- char * command_output
+ const char * executed_command,
+ const char * command_output
)
{
TARGET * built = (TARGET *)closure;
@@ -801,7 +831,7 @@ static void make1d( state * pState )
CMD * cmd = (CMD *)t->cmds;
int status = pState->status;
- if ( t->flags & T_FLAG_FAIL_EXPECTED )
+ if ( t->flags & T_FLAG_FAIL_EXPECTED && !globs.noexec )
{
/* Invert execution result when FAIL_EXPECTED has been applied. */
switch ( status )
@@ -823,9 +853,9 @@ static void make1d( state * pState )
if ( ( status == EXEC_CMD_FAIL ) && DEBUG_MAKE )
{
if ( !DEBUG_EXEC )
- printf( "%s\n", cmd->buf );
+ printf( "%s\n", cmd->buf->value );
- printf( "...failed %s ", cmd->rule->name );
+ printf( "...failed %s ", object_str( cmd->rule->name ) );
list_print( lol_get( &cmd->args, 0 ) );
printf( "...\n" );
}
@@ -842,16 +872,17 @@ static void make1d( state * pState )
if (status != EXEC_CMD_OK)
{
LIST * targets = lol_get( &cmd->args, 0 );
- for ( ; targets; targets = list_next( targets ) )
+ LISTITER iter = list_begin( targets ), end = list_end( targets );
+ for ( ; iter != end; iter = list_next( iter ) )
{
int need_unlink = 1;
- TARGET* t = bindtarget ( targets->string );
+ TARGET* t = bindtarget ( list_item( iter ) );
if (t->flags & T_FLAG_PRECIOUS)
{
need_unlink = 0;
}
- if (need_unlink && !unlink( targets->string ) )
- printf( "...removing %s\n", targets->string );
+ if (need_unlink && !unlink( object_str( list_item( iter ) ) ) )
+ printf( "...removing %s\n", object_str( list_item( iter ) ) );
}
}
@@ -878,29 +909,17 @@ static void swap_settings
TARGET * new_target
)
{
- if ( new_module == root_module() )
- new_module = 0;
-
if ( ( new_target == *current_target ) && ( new_module == *current_module ) )
return;
if ( *current_target )
- popsettings( (*current_target)->settings );
-
- if ( new_module != *current_module )
- {
- if ( *current_module )
- exit_module( *current_module );
+ popsettings( *current_module, (*current_target)->settings );
- *current_module = new_module;
-
- if ( new_module )
- enter_module( new_module );
- }
+ if ( new_target )
+ pushsettings( new_module, new_target->settings );
+ *current_module = new_module;
*current_target = new_target;
- if ( new_target )
- pushsettings( new_target->settings );
}
@@ -916,10 +935,11 @@ static void swap_settings
static CMD * make1cmds( TARGET * t )
{
CMD * cmds = 0;
- LIST * shell = 0;
+ LIST * shell = L0;
module_t * settings_module = 0;
TARGET * settings_target = 0;
ACTIONS * a0;
+ int 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.
@@ -939,10 +959,10 @@ static CMD * make1cmds( TARGET * t )
/* Only do rules with commands to execute. If this action has already
* been executed, use saved status.
*/
- if ( !actions || a0->action->running )
+ if ( !actions || a0->action->running >= running_flag )
continue;
- a0->action->running = 1;
+ a0->action->running = running_flag;
/* Make LISTS of targets and sources. If `execute together` has been
* specified for this rule, tack on sources from each instance of this
@@ -952,28 +972,30 @@ static CMD * make1cmds( TARGET * t )
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 )
+ if ( a1->action->rule == rule && a1->action->running < running_flag )
{
ns = make1list( ns, a1->action->sources, actions->flags );
- a1->action->running = 1;
+ a1->action->running = running_flag;
}
/* If doing only updated (or existing) sources, but none have been
* updated (or exist), skip this action.
*/
- if ( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
+ if ( list_empty( ns ) && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
{
list_free( nt );
continue;
}
swap_settings( &settings_module, &settings_target, rule->module, t );
- if ( !shell )
- shell = var_get( "JAMSHELL" ); /* shell is per-target */
+ if ( list_empty( shell ) )
+ {
+ shell = var_get( rule->module, constant_JAMSHELL ); /* shell is per-target */
+ }
/* If we had 'actions xxx bind vars' we bind the vars now. */
- boundvars = make1settings( actions->bindlist );
- pushsettings( boundvars );
+ boundvars = make1settings( rule->module, actions->bindlist );
+ pushsettings( rule->module, boundvars );
/*
* Build command, starting with all source args.
@@ -998,9 +1020,9 @@ static CMD * make1cmds( TARGET * t )
{
/* Build cmd: cmd_new consumes its lists. */
CMD * cmd = cmd_new( rule,
- list_copy( L0, nt ),
+ list_copy( nt ),
list_sublist( ns, start, chunk ),
- list_copy( L0, shell ) );
+ list_copy( shell ) );
if ( cmd )
{
@@ -1018,14 +1040,14 @@ static CMD * make1cmds( TARGET * t )
else
{
/* Too long and not splittable. */
- printf( "%s actions too long (max %d):\n", rule->name, MAXLINE
+ printf( "%s actions too long (max %d):\n", object_str( rule->name ), MAXLINE
);
/* Tell the user what didn't fit. */
- cmd = cmd_new( rule, list_copy( L0, nt ),
+ cmd = cmd_new( rule, list_copy( nt ),
list_sublist( ns, start, chunk ),
- list_new( L0, newstr( "%" ) ) );
- fputs( cmd->buf, stdout );
+ list_new( object_copy( constant_percent ) ) );
+ fputs( cmd->buf->value, stdout );
exit( EXITBAD );
}
}
@@ -1038,7 +1060,7 @@ static CMD * make1cmds( TARGET * t )
/* Free the variables whose values were bound by 'actions xxx bind
* vars'.
*/
- popsettings( boundvars );
+ popsettings( rule->module, boundvars );
freesettings( boundvars );
}
@@ -1077,16 +1099,16 @@ static LIST * make1list( LIST * l, TARGETS * targets, int flags )
/* Prohibit duplicates for RULE_TOGETHER. */
if ( flags & RULE_TOGETHER )
{
- LIST * m;
- for ( m = l; m; m = m->next )
- if ( !strcmp( m->string, t->boundname ) )
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for ( ; iter != end; iter = list_next( iter ) )
+ if ( object_equal( list_item( iter ), t->boundname ) )
break;
- if ( m )
+ if ( iter != end )
continue;
}
/* Build new list. */
- l = list_new( l, copystr( t->boundname ) );
+ l = list_push_back( l, object_copy( t->boundname ) );
}
return l;
@@ -1097,29 +1119,31 @@ static LIST * make1list( LIST * l, TARGETS * targets, int flags )
* make1settings() - for vars that get bound values, build up replacement lists.
*/
-static SETTINGS * make1settings( LIST * vars )
+static SETTINGS * make1settings( struct module_t * module, LIST * vars )
{
SETTINGS * settings = 0;
- for ( ; vars; vars = list_next( vars ) )
+ LISTITER vars_iter = list_begin( vars ), vars_end = list_end( vars );
+ for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) )
{
- LIST * l = var_get( vars->string );
- LIST * nl = 0;
+ LIST * l = var_get( module, list_item( vars_iter ) );
+ LIST * nl = L0;
+ LISTITER iter = list_begin( l ), end = list_end( l );
- for ( ; l; l = list_next( l ) )
+ for ( ; iter != end; iter = list_next( iter ) )
{
- TARGET * t = bindtarget( l->string );
+ TARGET * t = bindtarget( list_item( iter ) );
/* Make sure the target is bound. */
if ( t->binding == T_BIND_UNBOUND )
make1bind( t );
/* Build a new list. */
- nl = list_new( nl, copystr( t->boundname ) );
+ nl = list_push_back( nl, object_copy( t->boundname ) );
}
/* Add to settings chain. */
- settings = addsettings( settings, VAR_SET, vars->string, nl );
+ settings = addsettings( settings, VAR_SET, list_item( vars_iter ), nl );
}
return settings;
@@ -1138,8 +1162,9 @@ static void make1bind( TARGET * t )
if ( t->flags & T_FLAG_NOTFILE )
return;
- pushsettings( t->settings );
+ 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;
- popsettings( t->settings );
+ popsettings( root_module(), t->settings );
}
diff --git a/tools/build/v2/engine/modules.c b/tools/build/v2/engine/modules.c
index 7295259415..8898d18bb0 100644
--- a/tools/build/v2/engine/modules.c
+++ b/tools/build/v2/engine/modules.c
@@ -8,64 +8,54 @@
#include "modules.h"
#include "string.h"
#include "hash.h"
-#include "newstr.h"
+#include "object.h"
#include "lists.h"
#include "parse.h"
#include "rules.h"
#include "variable.h"
#include "strings.h"
+#include "native.h"
#include <assert.h>
static struct hash * module_hash = 0;
+static module_t root;
-
-static char * new_module_str( module_t * m, char * suffix )
-{
- char * result;
- string s;
- string_copy( &s, m->name );
- string_append( &s, suffix );
- result = newstr( s.value );
- string_free( &s );
- return result;
-}
-
-
-module_t * bindmodule( char * name )
+module_t * bindmodule( OBJECT * name )
{
- PROFILE_ENTER( BINDMODULE );
-
- string s;
- module_t m_;
- module_t * m = &m_;
-
- if ( !module_hash )
- module_hash = hashinit( sizeof( module_t ), "modules" );
- string_new( &s );
- if ( name )
+ if ( !name )
{
- string_append( &s, name );
- string_push_back( &s, '.' );
+ return &root;
}
-
- m->name = s.value;
-
- if ( hashenter( module_hash, (HASHDATA * *)&m ) )
+ else
{
- m->name = newstr( m->name );
- m->variables = 0;
- m->rules = 0;
- m->imported_modules = 0;
- m->class_module = 0;
- m->native_rules = 0;
- m->user_module = 0;
+ PROFILE_ENTER( BINDMODULE );
+
+ module_t * m;
+ int found;
+
+ if ( !module_hash )
+ module_hash = hashinit( sizeof( module_t ), "modules" );
+
+ m = (module_t *)hash_insert( module_hash, name, &found );
+ if ( !found )
+ {
+ m->name = object_copy( name );
+ m->variables = 0;
+ m->variable_indices = 0;
+ m->num_fixed_variables = 0;
+ m->fixed_variables = 0;
+ m->rules = 0;
+ m->imported_modules = 0;
+ m->class_module = 0;
+ m->native_rules = 0;
+ m->user_module = 0;
+ }
+
+ PROFILE_EXIT( BINDMODULE );
+
+ return m;
}
- string_free( &s );
-
- PROFILE_EXIT( BINDMODULE );
-
- return m;
}
/*
@@ -74,7 +64,7 @@ module_t * bindmodule( char * name )
struct hash * demand_rules( module_t * m )
{
if ( !m->rules )
- m->rules = hashinit( sizeof( RULE ), new_module_str( m, "rules" ) );
+ m->rules = hashinit( sizeof( RULE ), "rules" );
return m->rules;
}
@@ -89,43 +79,194 @@ static void delete_rule_( void * xrule, void * data )
}
+static void delete_native_rule( void * xrule, void * data )
+{
+ native_rule_t * rule = (native_rule_t *)xrule;
+ object_free( rule->name );
+ if ( rule->procedure )
+ function_free( rule->procedure );
+}
+
+
+static void delete_imported_modules( void * xmodule_name, void * data )
+{
+ object_free( *(OBJECT * *)xmodule_name );
+}
+
+static void free_fixed_variable( void * xvar, void * data );
+
void delete_module( module_t * m )
{
/* Clear out all the rules. */
if ( m->rules )
{
hashenumerate( m->rules, delete_rule_, (void *)0 );
- hashdone( m->rules );
+ hash_free( m->rules );
m->rules = 0;
}
+ if ( m->native_rules )
+ {
+ hashenumerate( m->native_rules, delete_native_rule, (void *)0 );
+ hash_free( m->native_rules );
+ m->native_rules = 0;
+ }
+
if ( m->variables )
{
- var_hash_swap( &m->variables );
- var_done();
- var_hash_swap( &m->variables );
+ var_done( m );
m->variables = 0;
}
+
+ if ( m->fixed_variables )
+ {
+ int i;
+ for ( i = 0; i < m->num_fixed_variables; ++i )
+ {
+ list_free( m->fixed_variables[ i ] );
+ }
+ BJAM_FREE( m->fixed_variables );
+ m->fixed_variables = 0;
+ }
+
+ if ( m->variable_indices )
+ {
+ hashenumerate( m->variable_indices, &free_fixed_variable, (void *)0 );
+ hash_free( m->variable_indices );
+ m->variable_indices = 0;
+ }
+
+ if ( m->imported_modules )
+ {
+ hashenumerate( m->imported_modules, delete_imported_modules, (void *)0 );
+ hash_free( m->imported_modules );
+ m->imported_modules = 0;
+ }
}
-module_t * root_module()
+struct module_stats
+{
+ OBJECT * module_name;
+ struct hashstats rules_stats[ 1 ];
+ struct hashstats variables_stats[ 1 ];
+ struct hashstats variable_indices_stats[ 1 ];
+ struct hashstats imported_modules_stats[ 1 ];
+};
+
+
+static void module_stat( struct hash * hp, OBJECT * module, const char * name )
+{
+ if ( hp )
+ {
+ struct hashstats stats[ 1 ];
+ string id[ 1 ];
+ hashstats_init( stats );
+ string_new( id );
+ string_append( id, object_str( module ) );
+ string_push_back( id, ' ' );
+ string_append( id, name );
+
+ hashstats_add( stats, hp );
+ hashstats_print( stats, id->value );
+
+ string_free( id );
+ }
+}
+
+
+static void class_module_stat( struct hashstats * stats, OBJECT * module, const char * name )
+{
+ if ( stats->item_size )
+ {
+ string id[ 1 ];
+ string_new( id );
+ string_append( id, object_str( module ) );
+ string_append( id, " object " );
+ string_append( id, name );
+
+ hashstats_print( stats, id->value );
+
+ string_free( id );
+ }
+}
+
+
+static void stat_module( void * xmodule, void * data )
+{
+ module_t *m = (module_t *)xmodule;
+
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ {
+ struct hash * class_info = (struct hash *)data;
+ if ( m->class_module )
+ {
+ int found;
+ struct module_stats * ms = (struct module_stats *)hash_insert( class_info, m->class_module->name, &found );
+ if ( !found )
+ {
+ ms->module_name = m->class_module->name;
+ hashstats_init( ms->rules_stats );
+ hashstats_init( ms->variables_stats );
+ hashstats_init( ms->variable_indices_stats );
+ hashstats_init( ms->imported_modules_stats );
+ }
+
+ hashstats_add( ms->rules_stats, m->rules );
+ hashstats_add( ms->variables_stats, m->variables );
+ hashstats_add( ms->variable_indices_stats, m->variable_indices );
+ hashstats_add( ms->imported_modules_stats, m->imported_modules );
+ }
+ else
+ {
+ module_stat( m->rules, m->name, "rules" );
+ module_stat( m->variables, m->name, "variables" );
+ module_stat( m->variable_indices, m->name, "fixed variables" );
+ module_stat( m->imported_modules, m->name, "imported modules" );
+ }
+ }
+
+ delete_module( m );
+ object_free( m->name );
+}
+
+static void print_class_stats( void * xstats, void * data )
{
- static module_t * root = 0;
- if ( !root )
- root = bindmodule( 0 );
- return root;
+ struct module_stats * stats = (struct module_stats *)xstats;
+ class_module_stat( stats->rules_stats, stats->module_name, "rules" );
+ class_module_stat( stats->variables_stats, stats->module_name, "variables" );
+ class_module_stat( stats->variable_indices_stats, stats->module_name, "fixed variables" );
+ class_module_stat( stats->imported_modules_stats, stats->module_name, "imported modules" );
}
-void enter_module( module_t * m )
+
+static void delete_module_( void * xmodule, void * data )
{
- var_hash_swap( &m->variables );
+ module_t *m = (module_t *)xmodule;
+
+ delete_module( m );
+ object_free( m->name );
}
-void exit_module( module_t * m )
+void modules_done()
+{
+ if ( DEBUG_MEM || DEBUG_PROFILE )
+ {
+ struct hash * class_hash = hashinit( sizeof( struct module_stats ), "object info" );
+ hashenumerate( module_hash, stat_module, (void *)class_hash );
+ hashenumerate( class_hash, print_class_stats, (void *)0 );
+ hash_free( class_hash );
+ }
+ hashenumerate( module_hash, delete_module_, (void *)0 );
+ hashdone( module_hash );
+ module_hash = 0;
+ delete_module( &root );
+}
+
+module_t * root_module()
{
- var_hash_swap( &m->variables );
+ return &root;
}
@@ -134,16 +275,22 @@ void import_module( LIST * module_names, module_t * target_module )
PROFILE_ENTER( IMPORT_MODULE );
struct hash * h;
+ LISTITER iter, end;
if ( !target_module->imported_modules )
target_module->imported_modules = hashinit( sizeof( char * ), "imported" );
h = target_module->imported_modules;
- for ( ; module_names; module_names = module_names->next )
+ iter = list_begin( module_names ), end = list_end( module_names );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- char * s = module_names->string;
- char * * ss = &s;
- hashenter( h, (HASHDATA * *)&ss );
+ int found;
+ OBJECT * s = list_item( iter );
+ OBJECT * * ss = (OBJECT * *)hash_insert( h, s, &found );
+ if( !found )
+ {
+ *ss = object_copy( s );
+ }
}
PROFILE_EXIT( IMPORT_MODULE );
@@ -152,10 +299,10 @@ void import_module( LIST * module_names, module_t * target_module )
static void add_module_name( void * r_, void * result_ )
{
- char * * r = (char * *)r_;
+ OBJECT * * r = (OBJECT * *)r_;
LIST * * result = (LIST * *)result_;
- *result = list_new( *result, copystr( *r ) );
+ *result = list_push_back( *result, object_copy( *r ) );
}
@@ -166,3 +313,124 @@ LIST * imported_modules( module_t * module )
hashenumerate( module->imported_modules, add_module_name, &result );
return result;
}
+
+
+FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, int * counter );
+FUNCTION * function_unbind_variables( FUNCTION * f );
+
+struct fixed_variable
+{
+ OBJECT * key;
+ int n;
+};
+
+struct bind_vars_t
+{
+ module_t * module;
+ 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 );
+}
+
+void module_bind_variables( struct module_t * m )
+{
+ if ( m != root_module() && m->rules )
+ {
+ struct bind_vars_t data;
+ data.module = m;
+ data.counter = m->num_fixed_variables;
+ hashenumerate( m->rules, &bind_variables_for_rule, &data );
+ module_set_fixed_variables( m, data.counter );
+ }
+}
+
+int module_add_fixed_var( struct module_t * m, OBJECT * name, int * counter )
+{
+ struct fixed_variable * v;
+ int found;
+
+ assert( !m->class_module );
+
+ if ( !m->variable_indices )
+ m->variable_indices = hashinit( sizeof( struct fixed_variable ), "variable index table" );
+
+ v = (struct fixed_variable *)hash_insert( m->variable_indices, name, &found );
+ if ( !found )
+ {
+ v->key = object_copy( name );
+ v->n = (*counter)++;
+ }
+
+ return v->n;
+}
+
+LIST * var_get_and_clear_raw( module_t * m, OBJECT * name );
+
+static void load_fixed_variable( void * xvar, void * data )
+{
+ 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 */
+ struct hash * variable_indices;
+ LIST * * fixed_variables = BJAM_MALLOC( n_variables * sizeof( LIST * ) );
+ if ( m->fixed_variables )
+ {
+ memcpy( fixed_variables, m->fixed_variables, n_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;
+ }
+ 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;
+ }
+}
diff --git a/tools/build/v2/engine/modules.h b/tools/build/v2/engine/modules.h
index 60053a239f..a7d9752b8c 100644
--- a/tools/build/v2/engine/modules.h
+++ b/tools/build/v2/engine/modules.h
@@ -10,28 +10,44 @@
struct module_t
{
- char* name;
- struct hash* rules;
- struct hash* variables;
- struct hash* imported_modules;
- struct module_t* class_module;
- struct hash* native_rules;
+ OBJECT * name;
+ struct hash * rules;
+ struct hash * variables;
+ struct hash * variable_indices;
+ int num_fixed_variables;
+ LIST * * fixed_variables;
+ struct hash * imported_modules;
+ struct 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( char* name );
-module_t* root_module();
-void enter_module( module_t* );
-void exit_module( module_t* );
-void delete_module( module_t* );
+module_t * bindmodule( OBJECT * name );
+module_t * root_module();
+void delete_module( module_t * );
-void import_module(LIST* module_names, module_t* target_module);
+void import_module( LIST * module_names, module_t * target_module );
LIST* imported_modules(module_t* module);
-struct hash* demand_rules( module_t* );
+struct hash * demand_rules( module_t * );
+void module_bind_variables( struct module_t * m );
+
+/*
+ * 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 );
+
+/*
+ * Returns the index of the variable or -1 if none exists.
+ */
+int module_get_fixed_var( struct module_t * m, OBJECT * name );
+
+void modules_done();
#endif
diff --git a/tools/build/v2/engine/modules/order.c b/tools/build/v2/engine/modules/order.c
index d77943a79c..ed632be3ac 100644
--- a/tools/build/v2/engine/modules/order.c
+++ b/tools/build/v2/engine/modules/order.c
@@ -5,18 +5,19 @@
#include "../native.h"
#include "../lists.h"
#include "../strings.h"
-#include "../newstr.h"
+#include "../object.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( PARSE *parse, FRAME *frame )
+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(arg->string, list_copy(0, arg->next), VAR_APPEND);
+ var_set( frame->module, list_item( iter ), list_copy_range( arg, list_next( iter ), end ), VAR_APPEND );
return L0;
}
@@ -24,11 +25,12 @@ LIST *add_pair( PARSE *parse, FRAME *frame )
/** Given a list and a value, returns position of that value in
the list, or -1 if not found.
*/
-int list_index(LIST* list, const char* value)
+int list_index(LIST* list, OBJECT* value)
{
int result = 0;
- for(; list; list = list->next, ++result) {
- if (strcmp(list->string, value) == 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))
return result;
}
return -1;
@@ -74,12 +76,12 @@ void topological_sort(int** graph, int num_vertices, int* result)
BJAM_FREE(colors);
}
-LIST *order( PARSE *parse, FRAME *frame )
+LIST *order( FRAME *frame, int flags )
{
- LIST* arg = lol_get( frame->args, 0 );
- LIST* tmp;
- LIST* result = 0;
+ LIST* arg = lol_get( frame->args, 0 );
+ LIST* result = L0;
int src;
+ LISTITER iter = list_begin(arg), end = list_end(arg);
/* We need to create a graph of order dependencies between
the passed objects. We assume that there are no duplicates
@@ -89,15 +91,16 @@ LIST *order( PARSE *parse, FRAME *frame )
int** graph = (int**)BJAM_CALLOC(length, sizeof(int*));
int* order = (int*)BJAM_MALLOC((length+1)*sizeof(int));
- for(tmp = arg, src = 0; tmp; tmp = tmp->next, ++src) {
+ 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(tmp->string);
+ LIST* dependencies = var_get(frame->module, list_item(iter));
int index = 0;
+ LISTITER dep_iter = list_begin(dependencies), dep_end = list_end(dependencies);
graph[src] = (int*)BJAM_CALLOC(list_length(dependencies)+1, sizeof(int));
- for(; dependencies; dependencies = dependencies->next) {
- int dst = list_index(arg, dependencies->string);
+ 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;
}
@@ -110,9 +113,9 @@ LIST *order( PARSE *parse, FRAME *frame )
int index = length-1;
for(; index >= 0; --index) {
int i;
- tmp = arg;
- for (i = 0; i < order[index]; ++i, tmp = tmp->next);
- result = list_new(result, tmp->string);
+ 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)));
}
}
@@ -131,12 +134,12 @@ LIST *order( PARSE *parse, FRAME *frame )
void init_order()
{
{
- char* args[] = { "first", "second", 0 };
+ const char* args[] = { "first", "second", 0 };
declare_native_rule("class@order", "add-pair", args, add_pair, 1);
}
{
- char* args[] = { "objects", "*", 0 };
+ const char* args[] = { "objects", "*", 0 };
declare_native_rule("class@order", "order", args, order, 1);
}
diff --git a/tools/build/v2/engine/modules/path.c b/tools/build/v2/engine/modules/path.c
index f5d0962246..ca243f03d6 100644
--- a/tools/build/v2/engine/modules/path.c
+++ b/tools/build/v2/engine/modules/path.c
@@ -4,17 +4,17 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
-LIST *path_exists( PARSE *parse, FRAME *frame )
+LIST *path_exists( FRAME *frame, int flags )
{
LIST* l = lol_get( frame->args, 0 );
time_t time;
- timestamp(l->string, &time);
+ timestamp(list_front(l), &time);
if (time != 0)
{
- return list_new(0, newstr("true"));
+ return list_new(object_new("true"));
}
else
{
@@ -25,7 +25,7 @@ LIST *path_exists( PARSE *parse, FRAME *frame )
void init_path()
{
{
- char* args[] = { "location", 0 };
+ const char* args[] = { "location", 0 };
declare_native_rule("path", "exists", args, path_exists, 1);
}
diff --git a/tools/build/v2/engine/modules/property-set.c b/tools/build/v2/engine/modules/property-set.c
index 2b0fb5d97b..9d0c5cf633 100644
--- a/tools/build/v2/engine/modules/property-set.c
+++ b/tools/build/v2/engine/modules/property-set.c
@@ -4,7 +4,7 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../strings.h"
#include "../lists.h"
#include "../variable.h"
@@ -19,7 +19,7 @@ LIST* get_grist(char* f)
string_new(s);
string_append_range(s, f, end+1);
- result = list_new(0, newstr(s->value));
+ result = list_new(object_new(s->value));
string_free(s);
return result;
@@ -41,17 +41,18 @@ rule create ( raw-properties * )
}
*/
-LIST *property_set_create( PARSE *parse, FRAME *frame )
+LIST *property_set_create( FRAME *frame, int flags )
{
LIST* properties = lol_get( frame->args, 0 );
- LIST* sorted = 0;
+ LIST* sorted = L0;
#if 0
LIST* order_sensitive = 0;
#endif
LIST* unique;
- LIST* tmp;
LIST* val;
string var[1];
+ OBJECT* name;
+ LISTITER iter, end;
#if 0
/* Sort all properties which are not order sensitive */
@@ -59,9 +60,9 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
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, tmp->string);
+ order_sensitive = list_new( order_sensitive, copystr(tmp->string));
} else {
- sorted = list_new( sorted, tmp->string);
+ sorted = list_new( sorted, copystr(tmp->string));
}
list_free(att);
}
@@ -76,22 +77,28 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
string_new(var);
string_append(var, ".ps.");
- for(tmp = unique; tmp; tmp = tmp->next) {
- string_append(var, tmp->string);
+ 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, '-');
}
- val = var_get(var->value);
- if (val == 0)
+ name = object_new(var->value);
+ val = var_get(frame->module, name);
+ if (list_empty(val))
{
- val = call_rule("new", frame,
- list_append(list_new(0, "property-set"), unique), 0);
+ OBJECT* rulename = object_new("new");
+ val = call_rule(rulename, frame,
+ list_append(list_new(object_new("property-set")), unique), 0);
+ object_free(rulename);
- var_set(newstr(var->value), list_copy(0, val), VAR_SET);
+ var_set(frame->module, name, list_copy(val), VAR_SET);
}
else
{
- val = list_copy(0, val);
+ list_free(unique);
+ val = list_copy(val);
}
+ object_free(name);
string_free(var);
/* The 'unique' variable is freed in 'call_rule'. */
@@ -104,7 +111,7 @@ LIST *property_set_create( PARSE *parse, FRAME *frame )
void init_property_set()
{
{
- char* args[] = { "raw-properties", "*", 0 };
+ const char* args[] = { "raw-properties", "*", 0 };
declare_native_rule("property-set", "create", args, property_set_create, 1);
}
}
diff --git a/tools/build/v2/engine/modules/regex.c b/tools/build/v2/engine/modules/regex.c
index d048ba1de4..9002f4bad3 100644
--- a/tools/build/v2/engine/modules/regex.c
+++ b/tools/build/v2/engine/modules/regex.c
@@ -4,7 +4,7 @@
#include "../native.h"
#include "../timestamp.h"
-#include "../newstr.h"
+#include "../object.h"
#include "../strings.h"
#include "../regexp.h"
#include "../compile.h"
@@ -25,7 +25,7 @@ rule transform ( list * : pattern : indices * )
return $(result) ;
}
*/
-LIST *regex_transform( PARSE *parse, FRAME *frame )
+LIST *regex_transform( FRAME *frame, int flags )
{
LIST* l = lol_get( frame->args, 0 );
LIST* pattern = lol_get( frame->args, 1 );
@@ -33,18 +33,19 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
int* indices = 0;
int size;
int* p;
- LIST* result = 0;
+ LIST* result = L0;
string buf[1];
string_new(buf);
- if (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; indices_list; indices_list = indices_list->next)
+ for(p = indices; iter != end; iter = list_next(iter))
{
- *p++ = atoi(indices_list->string);
+ *p++ = atoi(object_str(list_item(iter)));
}
}
else
@@ -56,11 +57,12 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
{
/* Result is cached and intentionally never freed */
- regexp *re = regex_compile( pattern->string );
+ regexp *re = regex_compile( list_front( pattern ) );
- for(; l; l = l->next)
+ LISTITER iter = list_begin( l ), end = list_end( l );
+ for( ; iter != end; iter = list_next( iter ) )
{
- if( regexec( re, l->string ) )
+ if( regexec( re, object_str( list_item( iter ) ) ) )
{
int i = 0;
for(; i < size; ++i)
@@ -73,7 +75,7 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
if (re->startp[index] != re->endp[index])
{
string_append_range( buf, re->startp[index], re->endp[index] );
- result = list_new( result, newstr( buf->value ) );
+ result = list_push_back( result, object_new( buf->value ) );
string_truncate( buf, 0 );
}
}
@@ -90,7 +92,7 @@ LIST *regex_transform( PARSE *parse, FRAME *frame )
void init_regex()
{
{
- char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
+ const char* args[] = { "list", "*", ":", "pattern", ":", "indices", "*", 0 };
declare_native_rule("regex", "transform", args, regex_transform, 2);
}
}
diff --git a/tools/build/v2/engine/modules/sequence.c b/tools/build/v2/engine/modules/sequence.c
index bda80d94c4..2b539966de 100644
--- a/tools/build/v2/engine/modules/sequence.c
+++ b/tools/build/v2/engine/modules/sequence.c
@@ -3,30 +3,35 @@
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include "../native.h"
+#include "../object.h"
# ifndef max
# define max( a,b ) ((a)>(b)?(a):(b))
# endif
-LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
+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 = 0;
+ LIST* result = L0;
LIST* tmp;
int highest_rank = -1;
- for (tmp = rank; tmp; tmp = tmp->next)
- highest_rank = max(highest_rank, atoi(tmp->string));
-
- for (; rank; rank = rank->next, elements = elements->next)
- if (atoi(rank->string) == highest_rank)
- result = list_new(result, elements->string);
+ 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)));
return result;
}
@@ -34,7 +39,7 @@ LIST *sequence_select_highest_ranked( PARSE *parse, FRAME *frame )
void init_sequence()
{
{
- char* args[] = { "elements", "*", ":", "rank", "*", 0 };
+ const char* args[] = { "elements", "*", ":", "rank", "*", 0 };
declare_native_rule("sequence", "select-highest-ranked", args,
sequence_select_highest_ranked, 1);
}
diff --git a/tools/build/v2/engine/modules/set.c b/tools/build/v2/engine/modules/set.c
index f8219403c5..77a314d57d 100644
--- a/tools/build/v2/engine/modules/set.c
+++ b/tools/build/v2/engine/modules/set.c
@@ -3,6 +3,7 @@
/* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include "../native.h"
+#include "../object.h"
/*
local result = ;
@@ -16,17 +17,18 @@
}
return $(result) ;
*/
-LIST *set_difference( PARSE *parse, FRAME *frame )
+LIST *set_difference( FRAME *frame, int flags )
{
LIST* b = lol_get( frame->args, 0 );
LIST* a = lol_get( frame->args, 1 );
- LIST* result = 0;
- for(; b; b = b->next)
+ LIST* result = L0;
+ LISTITER iter = list_begin( b ), end = list_end( b );
+ for( ; iter != end; iter = list_next( iter ) )
{
- if (!list_in(a, b->string))
- result = list_new(result, b->string);
+ if (!list_in(a, list_item(iter)))
+ result = list_push_back(result, object_copy(list_item(iter)));
}
return result;
}
@@ -34,7 +36,7 @@ LIST *set_difference( PARSE *parse, FRAME *frame )
void init_set()
{
{
- char* args[] = { "B", "*", ":", "A", "*", 0 };
+ const char* args[] = { "B", "*", ":", "A", "*", 0 };
declare_native_rule("set", "difference", args, set_difference, 1);
}
diff --git a/tools/build/v2/engine/native.c b/tools/build/v2/engine/native.c
index 4c2899595e..b1d4278313 100644
--- a/tools/build/v2/engine/native.c
+++ b/tools/build/v2/engine/native.c
@@ -4,33 +4,36 @@
#include "native.h"
#include "hash.h"
+#include "object.h"
+#include "assert.h"
-# define P0 (PARSE *)0
-# define C0 (char *)0
-
-
-void declare_native_rule(char* module, char* rule, char** args,
- LIST*(*f)(PARSE*, FRAME*), int version)
+void declare_native_rule( const char * module, const char * rule, const char * * args,
+ LIST * (*f)( FRAME *, int ), int version )
{
- module_t* m = bindmodule(module);
- if (m->native_rules == 0) {
+ OBJECT * module_obj = 0;
+ module_t * m;
+ if ( module )
+ {
+ module_obj = object_new( module );
+ }
+ 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");
}
{
- native_rule_t n, *np = &n;
- n.name = rule;
- if (args)
- {
- n.arguments = args_new();
- lol_build( n.arguments->data, args );
- }
- else
- {
- n.arguments = 0;
- }
- n.procedure = parse_make( f, P0, P0, P0, C0, C0, 0 );
- n.version = version;
- hashenter(m->native_rules, (HASHDATA**)&np);
+ native_rule_t *np;
+ OBJECT * name = object_new( rule );
+ int found;
+ np = (native_rule_t *)hash_insert( m->native_rules, name, &found );
+ np->name = name;
+ assert( !found );
+ np->procedure = function_builtin( f, 0, args );
+ np->version = version;
}
}
diff --git a/tools/build/v2/engine/native.h b/tools/build/v2/engine/native.h
index 3fc710b9c6..cdd63c844b 100644
--- a/tools/build/v2/engine/native.h
+++ b/tools/build/v2/engine/native.h
@@ -5,13 +5,16 @@
#ifndef NATIVE_H_VP_2003_12_09
#define NATIVE_H_VP_2003_12_09
+#include "lists.h"
+#include "object.h"
+#include "frames.h"
+#include "function.h"
#include "rules.h"
struct native_rule_t
{
- char* name;
- argument_list* arguments;
- PARSE* procedure;
+ 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
@@ -26,8 +29,8 @@ struct native_rule_t
/* MSVC debugger gets confused unless this is provided */
typedef struct native_rule_t native_rule_t ;
-void declare_native_rule(char* module, char* rule, char** args,
- LIST*(*f)(PARSE*, FRAME*), int version);
+void declare_native_rule( const char * module, const char * rule, const char * * args,
+ LIST * (*f)( FRAME *, int ), int version );
diff --git a/tools/build/v2/engine/newstr.c b/tools/build/v2/engine/newstr.c
deleted file mode 100644
index 6a229eb216..0000000000
--- a/tools/build/v2/engine/newstr.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-# include "jam.h"
-# include "newstr.h"
-# include "hash.h"
-# include "compile.h"
-# include <stddef.h>
-# include <stdlib.h>
-
-/*
- * newstr.c - string manipulation routines
- *
- * To minimize string copying, string creation, copying, and freeing
- * is done through newstr.
- *
- * External functions:
- *
- * newstr() - return a dynamically allocated copy of a string
- * copystr() - return a copy of a string previously returned by newstr()
- * freestr() - free a string returned by newstr() or copystr()
- * str_done() - free string tables
- *
- * Once a string is passed to newstr(), the returned string is readonly.
- *
- * This implementation builds a hash table of all strings, so that multiple
- * calls of newstr() on the same string allocate memory for the string once.
- * Strings are never actually freed.
- */
-
-typedef char * STRING;
-
-static struct hash * strhash = 0;
-static int strtotal = 0;
-static int strcount_in = 0;
-static int strcount_out = 0;
-
-
-/*
- * Immortal string allocator implementation speeds string allocation and cuts
- * down on internal fragmentation.
- */
-
-# define STRING_BLOCK 4096
-typedef struct strblock
-{
- struct strblock * next;
- char data[STRING_BLOCK];
-} strblock;
-
-static strblock * strblock_chain = 0;
-
-/* Storage remaining in the current strblock */
-static char * storage_start = 0;
-static char * storage_finish = 0;
-
-
-/*
- * allocate() - Allocate n bytes of immortal string storage.
- */
-
-static char * allocate( size_t const n )
-{
-#ifdef BJAM_NEWSTR_NO_ALLOCATE
- return (char*)BJAM_MALLOC_ATOMIC(n);
-#else
- /* See if we can grab storage from an existing block. */
- size_t remaining = storage_finish - storage_start;
- if ( remaining >= n )
- {
- char * result = storage_start;
- storage_start += n;
- return result;
- }
- else /* Must allocate a new block. */
- {
- strblock * new_block;
- size_t nalloc = n;
- if ( nalloc < STRING_BLOCK )
- 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] ) );
- if ( new_block == 0 )
- return 0;
- new_block->next = strblock_chain;
- strblock_chain = new_block;
-
- /* Take future allocations out of the larger remaining space. */
- if ( remaining < nalloc - n )
- {
- storage_start = new_block->data + n;
- storage_finish = new_block->data + nalloc;
- }
- return new_block->data;
- }
-#endif
-}
-
-
-/*
- * newstr() - return a dynamically allocated copy of a string.
- */
-
-char * newstr( char * string )
-{
- STRING str;
- STRING * s = &str;
-
- if ( !strhash )
- strhash = hashinit( sizeof( STRING ), "strings" );
-
- *s = string;
-
- if ( hashenter( strhash, (HASHDATA **)&s ) )
- {
- int l = strlen( string );
- char * m = (char *)allocate( l + 1 );
-
- strtotal += l + 1;
- memcpy( m, string, l + 1 );
- *s = m;
- }
-
- strcount_in += 1;
- return *s;
-}
-
-
-/*
- * copystr() - return a copy of a string previously returned by newstr()
- */
-
-char * copystr( char * s )
-{
- strcount_in += 1;
- return s;
-}
-
-
-/*
- * freestr() - free a string returned by newstr() or copystr()
- */
-
-void freestr( char * s )
-{
- strcount_out += 1;
-}
-
-
-/*
- * str_done() - free string tables.
- */
-
-void str_done()
-{
- /* Reclaim string blocks. */
- while ( strblock_chain != 0 )
- {
- strblock * n = strblock_chain->next;
- BJAM_FREE(strblock_chain);
- strblock_chain = n;
- }
-
- hashdone( strhash );
-
- if ( DEBUG_MEM )
- printf( "%dK in strings\n", strtotal / 1024 );
-
- /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
-}
diff --git a/tools/build/v2/engine/newstr.h b/tools/build/v2/engine/newstr.h
deleted file mode 100644
index 84a4d7b6da..0000000000
--- a/tools/build/v2/engine/newstr.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright 1993, 1995 Christopher Seiwald.
- *
- * This file is part of Jam - see jam.c for Copyright information.
- */
-
-/*
- * newstr.h - string manipulation routines
- */
-
-char * copystr ( char * );
-void freestr ( char * );
-char * newstr ( char * );
-void str_done();
diff --git a/tools/build/v2/engine/object.c b/tools/build/v2/engine/object.c
new file mode 100644
index 0000000000..399f04ae84
--- /dev/null
+++ b/tools/build/v2/engine/object.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright 1993, 1995 Christopher Seiwald.
+ * Copyright 2011 Steven Watanabe
+ *
+ * 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
+ *
+ * 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.
+ */
+
+#define OBJECT_MAGIC 0xa762e0e3u
+
+#ifndef object_copy
+
+struct hash_header
+{
+#ifndef NDEBUG
+ unsigned int magic;
+#endif
+ unsigned int hash;
+ struct hash_item * next;
+};
+
+#endif
+
+struct hash_item
+{
+ struct hash_header header;
+ char data[1];
+};
+
+#define ALLOC_ALIGNMENT ( sizeof( struct hash_item ) - sizeof( struct hash_header ) )
+
+typedef struct string_set
+{
+ unsigned int num;
+ unsigned int size;
+ struct hash_item * * data;
+} string_set;
+
+static string_set strhash;
+static int strtotal = 0;
+static int strcount_in = 0;
+static int strcount_out = 0;
+
+
+/*
+ * Immortal string allocator implementation speeds string allocation and cuts
+ * down on internal fragmentation.
+ */
+
+# define STRING_BLOCK 4096
+typedef struct strblock
+{
+ struct strblock * next;
+ char data[STRING_BLOCK];
+} strblock;
+
+static strblock * strblock_chain = 0;
+
+/* Storage remaining in the current strblock */
+static char * storage_start = 0;
+static char * storage_finish = 0;
+
+
+/*
+ * allocate() - Allocate n bytes of immortal string storage.
+ */
+
+static char * allocate( size_t n )
+{
+#ifdef BJAM_NEWSTR_NO_ALLOCATE
+ 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;
+ if ( remaining >= n )
+ {
+ char * result = storage_start;
+ storage_start += n;
+ return result;
+ }
+ else /* Must allocate a new block. */
+ {
+ strblock * new_block;
+ size_t nalloc = n;
+ if ( nalloc < STRING_BLOCK )
+ 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] ) );
+ if ( new_block == 0 )
+ return 0;
+ new_block->next = strblock_chain;
+ strblock_chain = new_block;
+
+ /* Take future allocations out of the larger remaining space. */
+ if ( remaining < nalloc - n )
+ {
+ storage_start = new_block->data + n;
+ storage_finish = new_block->data + nalloc;
+ }
+ return new_block->data;
+ }
+#endif
+}
+
+static unsigned int hash_keyval( const char * key )
+{
+ unsigned int hash = 0;
+ unsigned i;
+ unsigned int len = strlen( key );
+
+ for ( i = 0; i < len / sizeof( unsigned int ); ++i )
+ {
+ unsigned int val;
+ memcpy( &val, key, sizeof( unsigned int ) );
+ hash = hash * 2147059363 + val;
+ key += sizeof( unsigned int );
+ }
+
+ {
+ unsigned int val = 0;
+ memcpy( &val, key, len % sizeof( unsigned int ) );
+ hash = hash * 2147059363 + val;
+ }
+
+ hash += (hash >> 17);
+
+ return hash;
+}
+
+static void string_set_init(string_set * set)
+{
+ set->size = 0;
+ set->num = 4;
+ set->data = (struct hash_item * *)BJAM_MALLOC( set->num * sizeof( struct hash_item * ) );
+ memset( set->data, 0, set->num * sizeof( struct hash_item * ) );
+}
+
+static void string_set_done(string_set * set)
+{
+ BJAM_FREE( set->data );
+}
+
+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);
+ for ( i = 0; i < set->num; ++i )
+ {
+ while ( 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;
+ }
+ }
+ BJAM_FREE( set->data );
+ *set = new_set;
+}
+
+static const char * string_set_insert ( string_set * set, const char * string )
+{
+ unsigned hash = hash_keyval( string );
+ 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 )
+ {
+ return result->data;
+ }
+ }
+
+ 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->header.hash = hash;
+ 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;
+ ++set->size;
+
+ return result->data;
+}
+
+
+static struct hash_item * object_get_item( OBJECT * obj )
+{
+ return (struct hash_item *)( (char *)obj - offsetof( struct hash_item, data ) );
+}
+
+
+static void object_validate( OBJECT * obj )
+{
+ assert( object_get_item( obj )->header.magic == OBJECT_MAGIC );
+}
+
+
+/*
+ * object_new() - create an object from a string.
+ */
+
+OBJECT * object_new( const char * string )
+{
+#ifdef BJAM_NO_MEM_CACHE
+ int l = strlen( string );
+ struct hash_item * m = (struct hash_item *)BJAM_MALLOC( sizeof(struct hash_header) + l + 1 );
+
+ strtotal += l + 1;
+ memcpy( m->data, string, l + 1 );
+ m->header.magic = OBJECT_MAGIC;
+ return (OBJECT *)m->data;
+#else
+ if ( ! strhash.data )
+ string_set_init( &strhash );
+
+ strcount_in += 1;
+
+ return (OBJECT *)string_set_insert( &strhash, string );
+#endif
+}
+
+#ifndef object_copy
+
+/*
+ * object_copy() - return a copy of an object
+ */
+
+OBJECT * object_copy( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ return object_new( object_str( obj ) );
+#else
+ strcount_in += 1;
+ return obj;
+#endif
+}
+
+
+/*
+ * object_free() - free an object
+ */
+
+void object_free( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ BJAM_FREE( object_get_item( obj ) );
+#endif
+ strcount_out += 1;
+}
+
+
+/*
+ * object_str() - return the
+ */
+
+const char * object_str( OBJECT * obj )
+{
+ object_validate( obj );
+ return (const char *)obj;
+}
+
+
+/*
+ * object_equal() - compare two objects
+ */
+
+int object_equal( OBJECT * lhs, OBJECT * rhs )
+{
+ object_validate( lhs );
+ object_validate( rhs );
+#ifdef BJAM_NO_MEM_CACHE
+ return strcmp(object_str(lhs), object_str(rhs)) == 0;
+#else
+ assert( (lhs == rhs) == ( strcmp(object_str(lhs), object_str(rhs)) == 0 ) );
+ return lhs == rhs;
+#endif
+}
+
+
+/*
+ * object_hash() - returns the hash value of an object
+ */
+
+unsigned int object_hash( OBJECT * obj )
+{
+ object_validate( obj );
+#ifdef BJAM_NO_MEM_CACHE
+ return hash_keyval( object_str( obj ) );
+#else
+ return object_get_item( obj )->header.hash;
+#endif
+}
+
+#endif
+
+/*
+ * object_done() - free string tables.
+ */
+
+void object_done()
+{
+
+#ifdef BJAM_NEWSTR_NO_ALLOCATE
+
+ unsigned i;
+
+ for ( i = 0; i < strhash.num; ++i )
+ {
+ while ( strhash.data[i] )
+ {
+ struct hash_item * item = strhash.data[i];
+ strhash.data[i] = item->header.next;
+ BJAM_FREE( item );
+ }
+ }
+
+#else
+
+ /* Reclaim string blocks. */
+ while ( strblock_chain != 0 )
+ {
+ strblock * 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 ); */
+}
diff --git a/tools/build/v2/engine/object.h b/tools/build/v2/engine/object.h
new file mode 100644
index 0000000000..1c123f8b0f
--- /dev/null
+++ b/tools/build/v2/engine/object.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Steven Watanabe
+ *
+ * This file is part of Jam - see jam.c for Copyright information.
+ */
+
+/*
+ * object.h - object manipulation routines
+ */
+
+#ifndef BOOST_JAM_OBJECT_H
+#define BOOST_JAM_OBJECT_H
+
+typedef struct _object OBJECT;
+
+OBJECT * object_new ( const char * );
+void object_done ( void );
+
+#if defined(NDEBUG) && !defined(BJAM_NO_MEM_CACHE)
+
+struct hash_header
+{
+ unsigned int hash;
+ 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 )
+
+#else
+
+const char * object_str ( OBJECT * );
+OBJECT * object_copy ( OBJECT * );
+void object_free ( OBJECT * );
+int object_equal ( OBJECT *, OBJECT * );
+unsigned int object_hash ( OBJECT * );
+
+#endif
+
+#endif
diff --git a/tools/build/v2/engine/output.c b/tools/build/v2/engine/output.c
index 483c6ca9e6..a0154c6ea3 100644
--- a/tools/build/v2/engine/output.c
+++ b/tools/build/v2/engine/output.c
@@ -6,7 +6,7 @@
#include "jam.h"
#include "output.h"
-#include "newstr.h"
+#include "object.h"
#include <stdio.h>
#define bjam_out (stdout)
@@ -101,25 +101,25 @@ void out_action
}
-char * outf_int( int value )
+OBJECT * outf_int( int value )
{
char buffer[50];
sprintf( buffer, "%i", value );
- return newstr( buffer );
+ return object_new( buffer );
}
-char * outf_double( double value )
+OBJECT * outf_double( double value )
{
char buffer[50];
sprintf( buffer, "%f", value );
- return newstr( buffer );
+ return object_new( buffer );
}
-char * outf_time( time_t value )
+OBJECT * outf_time( time_t value )
{
char buffer[50];
strftime( buffer, 49, "%Y-%m-%d %H:%M:%SZ", gmtime( &value ) );
- return newstr( buffer );
+ return object_new( buffer );
}
diff --git a/tools/build/v2/engine/output.h b/tools/build/v2/engine/output.h
index 9e9876cfc5..64175e67ef 100644
--- a/tools/build/v2/engine/output.h
+++ b/tools/build/v2/engine/output.h
@@ -7,6 +7,7 @@
#ifndef BJAM_OUTPUT_H
#define BJAM_OUTPUT_H
+#include "object.h"
#include <time.h>
#define EXIT_OK 0
@@ -22,8 +23,8 @@ void out_action(
int exit_reason
);
-char * outf_int( int value );
-char * outf_double( double value );
-char * outf_time( time_t value );
+OBJECT * outf_int( int value );
+OBJECT * outf_double( double value );
+OBJECT * outf_time( time_t value );
#endif
diff --git a/tools/build/v2/engine/parse.c b/tools/build/v2/engine/parse.c
index 9114fa057a..167ad1745a 100644
--- a/tools/build/v2/engine/parse.c
+++ b/tools/build/v2/engine/parse.c
@@ -14,9 +14,10 @@
#include "lists.h"
#include "parse.h"
#include "scan.h"
-#include "newstr.h"
+#include "object.h"
#include "modules.h"
#include "frames.h"
+#include "function.h"
/*
* parse.c - make and destroy parse trees as driven by the parser
@@ -29,7 +30,7 @@
static PARSE * yypsave;
-void parse_file( char * f, FRAME * frame )
+void parse_file( OBJECT * f, FRAME * frame )
{
/* Suspend scan of current file and push this new file in the stream. */
yyfparse( f );
@@ -41,6 +42,7 @@ void parse_file( char * f, FRAME * frame )
for ( ; ; )
{
PARSE * p;
+ FUNCTION * func;
/* Filled by yyparse() calling parse_save(). */
yypsave = 0;
@@ -50,8 +52,10 @@ void parse_file( char * f, FRAME * frame )
break;
/* Run the parse tree. */
- parse_evaluate( p, frame );
+ func = function_compile( p );
parse_free( p );
+ list_free( function_run( func, frame, stack_global() ) );
+ function_free( func );
}
}
@@ -63,17 +67,17 @@ void parse_save( PARSE * p )
PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
- PARSE * left,
- PARSE * right,
- PARSE * third,
- char * string,
- char * string1,
- int num )
+ int type,
+ PARSE * left,
+ PARSE * right,
+ PARSE * third,
+ OBJECT * string,
+ OBJECT * string1,
+ int num )
{
PARSE * p = (PARSE *)BJAM_MALLOC( sizeof( PARSE ) );
- p->func = func;
+ p->type = type;
p->left = left;
p->right = right;
p->third = third;
@@ -85,12 +89,13 @@ PARSE * parse_make(
if ( left )
{
- p->file = left->file;
+ p->file = object_copy( left->file );
p->line = left->line;
}
else
{
yyinput_stream( &p->file, &p->line );
+ p->file = object_copy( p->file );
}
return p;
@@ -109,9 +114,9 @@ void parse_free( PARSE * p )
return;
if ( p->string )
- freestr( p->string );
+ object_free( p->string );
if ( p->string1 )
- freestr( p->string1 );
+ object_free( p->string1 );
if ( p->left )
parse_free( p->left );
if ( p->right )
@@ -119,14 +124,9 @@ void parse_free( PARSE * p )
if ( p->third )
parse_free( p->third );
if ( p->rulename )
- freestr( p->rulename );
+ object_free( p->rulename );
+ if ( p->file )
+ object_free( p->file );
BJAM_FREE( (char *)p );
}
-
-
-LIST * parse_evaluate( PARSE * p, FRAME * frame )
-{
- frame->procedure = p;
- return (*p->func)( p, frame );
-}
diff --git a/tools/build/v2/engine/parse.h b/tools/build/v2/engine/parse.h
index e324972f7b..882a029f42 100644
--- a/tools/build/v2/engine/parse.h
+++ b/tools/build/v2/engine/parse.h
@@ -21,36 +21,55 @@
* parse.h - make and destroy parse trees as driven by the parser.
*/
+#define PARSE_APPEND 0
+#define PARSE_FOREACH 1
+#define PARSE_IF 2
+#define PARSE_EVAL 3
+#define PARSE_INCLUDE 4
+#define PARSE_LIST 5
+#define PARSE_LOCAL 6
+#define PARSE_MODULE 7
+#define PARSE_CLASS 8
+#define PARSE_NULL 9
+#define PARSE_ON 10
+#define PARSE_RULE 11
+#define PARSE_RULES 12
+#define PARSE_SET 13
+#define PARSE_SETCOMP 14
+#define PARSE_SETEXEC 15
+#define PARSE_SETTINGS 16
+#define PARSE_SWITCH 17
+#define PARSE_WHILE 18
+
/*
* Parse tree node.
*/
struct _PARSE {
- LIST * (* func)( PARSE *, FRAME * );
+ int type;
PARSE * left;
PARSE * right;
PARSE * third;
- char * string;
- char * string1;
+ OBJECT * string;
+ OBJECT * string1;
int num;
int refs;
-/* module * module; */
- char * rulename;
- char * file;
+ OBJECT * rulename;
+ OBJECT * file;
int line;
};
-void parse_file( char *, FRAME * );
+void parse_file( OBJECT *, FRAME * );
void parse_save( PARSE * );
PARSE * parse_make(
- LIST * (* func)( PARSE *, FRAME * ),
- PARSE * left,
- PARSE * right,
- PARSE * third,
- char * string,
- char * string1,
- int num );
+ int type,
+ PARSE * left,
+ PARSE * right,
+ PARSE * third,
+ OBJECT * string,
+ OBJECT * string1,
+ int num );
void parse_refer ( PARSE * );
void parse_free ( PARSE * );
diff --git a/tools/build/v2/engine/patchlevel.h b/tools/build/v2/engine/patchlevel.h
index 699efd84ba..18224c1c31 100644
--- a/tools/build/v2/engine/patchlevel.h
+++ b/tools/build/v2/engine/patchlevel.h
@@ -8,10 +8,10 @@
/* It can be accessed as $(JAMVERSION) in the Jamfile. */
#define VERSION_MAJOR 2011
-#define VERSION_MINOR 04
+#define VERSION_MINOR 12
#define VERSION_PATCH 0
#define VERSION_MAJOR_SYM "2011"
-#define VERSION_MINOR_SYM "04"
+#define VERSION_MINOR_SYM "12"
#define VERSION_PATCH_SYM "00"
-#define VERSION "2011.4"
-#define JAMVERSYM "JAMVERSION=2011.4"
+#define VERSION "2011.12"
+#define JAMVERSYM "JAMVERSION=2011.12"
diff --git a/tools/build/v2/engine/pathmac.c b/tools/build/v2/engine/pathmac.c
deleted file mode 100644
index e2c250e338..0000000000
--- a/tools/build/v2/engine/pathmac.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * 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)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-
-# ifdef OS_MAC
-
-# define DELIM ':'
-
-/*
- * pathunix.c - manipulate file names on UNIX, NT, OS2
- *
- * 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/10/01 (seiwald) - path_parse now strips the trailing : from the
- * directory name, unless the directory name is all
- * :'s, so that $(d:P) works.
- */
-
-/*
- * path_parse() - split a file name into dir/base/suffix/member
- */
-
-void
-path_parse(
- char *file,
- PATHNAME *f )
-{
- char *p, *q;
- 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: */
-
- if ( p = strrchr( file, DELIM ) )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p - file;
- file = p + 1;
-
- /* All :'s? Include last : as part of directory name */
-
- while ( ( p > f->f_dir.ptr ) && ( *--p == DELIM ) );
-
- if ( p == f->f_dir.ptr )
- ++f->f_dir.len;
- }
-
- 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 = memchr( q, '.', end - q ) )
- p = q++;
-
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
-
- /* Leaves base */
-
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-}
-
-/*
- * path_build() - build a filename given dir/base/suffix/member.
- */
-
-# define DIR_EMPTY 0 /* "" */
-# define DIR_DOT 1 /* : */
-# define DIR_DOTDOT 2 /* :: */
-# define DIR_ABS 3 /* dira:dirb: */
-# define DIR_REL 4 /* :dira:dirb: */
-
-# define G_DIR 0 /* take dir */
-# define G_ROOT 1 /* take root */
-# define G_CAT 2 /* prepend root to dir */
-# define G_DTDR 3 /* :: of rel dir */
-# define G_DDDD 4 /* make it ::: (../..) */
-# define G_MT 5 /* leave it empty */
-
-char grid[5][5] = {
-/* EMPTY DOT DOTDOT ABS REL */
-/* EMPTY */ { G_MT, G_DIR, G_DIR, G_DIR, G_DIR },
-/* DOT */ { G_ROOT, G_DIR, G_DIR, G_DIR, G_DIR },
-/* DOTDOT */ { G_ROOT, G_ROOT, G_DDDD, G_DIR, G_DTDR },
-/* ABS */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT },
-/* REL */ { G_ROOT, G_ROOT, G_ROOT, G_DIR, G_CAT }
-};
-
-static int file_flags( char * ptr, int len )
-{
- if ( !len )
- return DIR_EMPTY;
- if ( ( len == 1 ) && ( ptr[0] == DELIM ) )
- return DIR_DOT;
- if ( ( len == 2 ) && ( ptr[0] == DELIM ) && ( ptr[1] == DELIM ) )
- return DIR_DOTDOT;
- if ( ptr[0] == DELIM )
- return DIR_REL;
- return DIR_ABS;
-}
-
-
-void path_build( PATHNAME * f, string * file, int binding )
-{
- int dflag;
- int rflag;
- int act;
-
- file_build1( f, file );
-
- /* Combine root & directory, according to the grid. */
-
- dflag = file_flags( f->f_dir.ptr, f->f_dir.len );
- rflag = file_flags( f->f_root.ptr, f->f_root.len );
-
- switch ( act = grid[ rflag ][ dflag ] )
- {
- case G_DTDR:
- {
- /* :: of rel dir */
- string_push_back( file, DELIM );
- }
- /* fall through */
-
- case G_DIR:
- /* take dir */
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_ROOT:
- /* take root */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- break;
-
- case G_CAT:
- /* prepend root to dir */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- if ( file->value[ file->size - 1 ] == DELIM )
- string_pop_back( file );
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_DDDD:
- /* make it ::: (../..) */
- string_append( file, ":::" );
- break;
- }
-
- /* Put : between dir and file (if none already). */
-
- if ( ( act != G_MT ) &&
- ( file->value[ file->size - 1 ] != DELIM ) &&
- ( f->f_base.len || f->f_suffix.len ) )
- {
- string_push_back( file, DELIM );
- }
-
- 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, ')' );
- }
-
- if ( DEBUG_SEARCH )
- printf( " -> '%s'\n", file->value );
-}
-
-
-/*
- * path_parent() - make a PATHNAME point to its parent dir
- */
-
-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;
-}
-
-# endif /* OS_MAC */
diff --git a/tools/build/v2/engine/pathsys.h b/tools/build/v2/engine/pathsys.h
index 737758105f..978dbf4a7a 100644
--- a/tools/build/v2/engine/pathsys.h
+++ b/tools/build/v2/engine/pathsys.h
@@ -15,31 +15,27 @@
* 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.
- *
- * On VMS, we keep track of whether the original path was a directory
- * (without a file), so that $(VAR:D) can climb to the parent.
*/
#ifndef PATHSYS_VP_20020211_H
# define PATHSYS_VP_20020211_H
+#include "jam.h"
#include "strings.h"
+#include "object.h"
typedef struct _pathname PATHNAME;
typedef struct _pathpart PATHPART;
struct _pathpart
{
- char * ptr;
- int len;
+ const char * ptr;
+ int len;
};
struct _pathname
{
PATHPART part[6];
-#ifdef OS_VMS
- int parent;
-#endif
#define f_grist part[0]
#define f_root part[1]
@@ -52,18 +48,26 @@ struct _pathname
void path_build( PATHNAME * f, string * file, int binding );
void path_build1( PATHNAME * f, string * file );
-void path_parse( char * file, PATHNAME * f );
+void path_parse( const char * file, PATHNAME * f );
void path_parent( PATHNAME * f );
#ifdef NT
-/** Returns newstr-allocated string with long equivivalent of 'short_name'.
+/** 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. */
-char * short_path_to_long_path( char * short_path );
+OBJECT * short_path_to_long_path( OBJECT * short_path );
#endif
+/** 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.
+ */
+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.
@@ -72,11 +76,11 @@ const char * path_tmpdir( void );
/** Returns a new temporary name.
*/
-const char * path_tmpnam( void );
+OBJECT * path_tmpnam( void );
/** Returns a new temporary path.
*/
-const char * path_tmpfile( void );
+OBJECT * path_tmpfile( void );
#endif
/** Give the first argument to 'main', return a full path to
@@ -86,6 +90,8 @@ const char * path_tmpfile( void );
Implemented in jam.c
*/
-char * executable_path (char *argv0);
+char * executable_path (const char *argv0);
+
+void path_done( void );
#endif
diff --git a/tools/build/v2/engine/pathunix.c b/tools/build/v2/engine/pathunix.c
index 2daad14b72..a8428df8d6 100644
--- a/tools/build/v2/engine/pathunix.c
+++ b/tools/build/v2/engine/pathunix.c
@@ -14,10 +14,11 @@
# include "jam.h"
# include "pathsys.h"
# include "strings.h"
-# include "newstr.h"
+# include "object.h"
# include "filesys.h"
# include <time.h>
# include <stdlib.h>
+# include <assert.h>
# ifndef OS_NT
# include <unistd.h>
# endif
@@ -56,11 +57,11 @@
* path_parse() - split a file name into dir/base/suffix/member
*/
-void path_parse( char * file, PATHNAME * f )
+void path_parse( const char * file, PATHNAME * f )
{
- char * p;
- char * q;
- char * end;
+ const char * p;
+ const char * q;
+ const char * end;
memset( (char *)f, 0, sizeof( *f ) );
@@ -273,124 +274,250 @@ path_parent( PATHNAME *f )
#ifdef NT
#include <windows.h>
-#include <tchar.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 );
-DWORD ShortPathToLongPath(LPCTSTR lpszShortPath,LPTSTR lpszLongPath,DWORD
- cchBuffer)
+void ShortPathToLongPath( char * short_path, string * out )
{
- LONG i=0;
- TCHAR path[_MAX_PATH]={0};
- TCHAR ret[_MAX_PATH]={0};
- LONG pos=0, prev_pos=0;
- LONG len=_tcslen(lpszShortPath);
-
- /* Is the string valid? */
- if (!lpszShortPath) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return 0;
+ 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 );
+ }
}
+}
- /* Is the path valid? */
- if (GetFileAttributes(lpszShortPath)==INVALID_FILE_ATTRIBUTES)
- return 0;
+OBJECT * short_path_to_long_path( OBJECT * short_path )
+{
+ return path_as_key( short_path );
+}
- /* Convert "/" to "\" */
- for (i=0;i<len;++i) {
- if (lpszShortPath[i]==_T('/'))
- path[i]=_T('\\');
+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
- path[i]=lpszShortPath[i];
+ *s = tolower( *s );
+ }
+ /* Strip trailing "/" */
+ if ( path->size != 0 && path->size != 3 && path->value[ path->size - 1 ] == '\\' )
+ {
+ string_pop_back( path );
}
+}
- /* UNC path? */
- if (path[0]==_T('\\') && path[1]==_T('\\')) {
- pos=2;
- for (i=0;i<2;++i) {
- while (path[pos]!=_T('\\') && path[pos]!=_T('\0'))
- ++pos;
- ++pos;
+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 );
}
- _tcsncpy(ret,path,pos-1);
- } /* Drive letter? */
- else if (path[1]==_T(':')) {
- if (path[2]==_T('\\'))
- pos=3;
- if (len==3) {
- if (cchBuffer>3)
- _tcscpy(lpszLongPath,lpszShortPath);
- return len;
+ object_free( normalized );
+ if ( nresult != result )
+ {
+ result->path = object_copy( path );
+ result->key = object_copy( nresult->key );
}
- _tcsncpy(ret,path,2);
}
+}
+
+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" );
- /* Expand the path for each subpath, and strip trailing backslashes */
- for (prev_pos = pos-1;pos<=len;++pos) {
- if (path[pos]==_T('\\') || (path[pos]==_T('\0') &&
- path[pos-1]!=_T('\\'))) {
- WIN32_FIND_DATA fd;
- HANDLE hf=0;
- TCHAR c=path[pos];
- char* new_element;
- path[pos]=_T('\0');
-
- /* the path[prev_pos+1]... path[pos] range is the part of
- path we're handling right now. We need to find long
- name for that element and add it. */
- new_element = path + prev_pos + 1;
-
- /* First add separator, but only if there's something in result already. */
- if (ret[0] != _T('\0'))
- {
- _tcscat(ret,_T("\\"));
- }
-
- /* If it's ".." element, we need to append it, not
- the name in parent that FindFirstFile will return.
- Same goes for "." */
-
- if (new_element[0] == _T('.') && new_element[1] == _T('\0') ||
- new_element[0] == _T('.') && new_element[1] == _T('.')
- && new_element[2] == _T('\0'))
- {
- _tcscat(ret, new_element);
- }
- else
- {
- hf=FindFirstFile(path, &fd);
- if (hf==INVALID_HANDLE_VALUE)
- return 0;
-
- _tcscat(ret,fd.cFileName);
- FindClose(hf);
- }
-
- path[pos]=c;
-
- prev_pos = pos;
+ 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 );
}
+}
- len=_tcslen(ret)+1;
- if (cchBuffer>=len)
- _tcscpy(lpszLongPath,ret);
+#else
- return len;
+void path_add_key( OBJECT * path )
+{
}
-char* short_path_to_long_path(char* short_path)
+OBJECT * path_as_key( OBJECT * path )
{
- char buffer2[_MAX_PATH];
- int ret = ShortPathToLongPath(short_path, buffer2, _MAX_PATH);
+ return object_copy( path );
+}
- if (ret)
- return newstr(buffer2);
- else
- return newstr(short_path);
+void path_done( void )
+{
}
#endif
@@ -424,7 +551,7 @@ const char * path_tmpdir()
return path_tmpdir_result;
}
-const char * path_tmpnam(void)
+OBJECT * path_tmpnam(void)
{
char name_buffer[64];
# ifdef OS_NT
@@ -436,18 +563,21 @@ const char * path_tmpnam(void)
if (0 == c1) c1 = time(0)&0xffff;
c1 += 1;
sprintf(name_buffer,"jam%lx%lx.000",c0,c1);
- return newstr(name_buffer);
+ return object_new(name_buffer);
}
-const char * path_tmpfile(void)
+OBJECT * path_tmpfile(void)
{
- const char * result = 0;
+ OBJECT * result = 0;
+ OBJECT * tmpnam;
string file_path;
string_copy(&file_path,path_tmpdir());
string_push_back(&file_path,PATH_DELIM);
- string_append(&file_path,path_tmpnam());
- result = newstr(file_path.value);
+ 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;
diff --git a/tools/build/v2/engine/pathvms.c b/tools/build/v2/engine/pathvms.c
deleted file mode 100644
index 975fe5a579..0000000000
--- a/tools/build/v2/engine/pathvms.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
- *
- * 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)
- */
-
-# include "jam.h"
-# include "pathsys.h"
-
-# ifdef OS_VMS
-
-# define DEBUG
-
-/*
- * pathvms.c - manipulate file names on VMS
- *
- * 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.
- *
- * WARNING! This file contains voodoo logic, as black magic is
- * necessary for wrangling with VMS file name. Woe be to people
- * who mess with this code.
- *
- * 02/09/95 (seiwald) - bungled R=[xxx] - was using directory length!
- * 05/03/96 (seiwald) - split from filevms.c
- */
-
-/*
- * path_parse() - split a file name into dir/base/suffix/member.
- */
-
-void path_parse( char * file, PATHNAME * f )
-{
- char * p;
- char * q;
- 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 dev:[dir] or dev: */
-
- if ( ( p = strchr( file, ']' ) ) || ( p = strchr( file, ':' ) ) )
- {
- f->f_dir.ptr = file;
- f->f_dir.len = p + 1 - file;
- 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++;
-
- if ( p )
- {
- f->f_suffix.ptr = p;
- f->f_suffix.len = end - p;
- end = p;
- }
-
- /* Leaves base. */
- f->f_base.ptr = file;
- f->f_base.len = end - file;
-
- /* Is this a directory without a file spec? */
- f->parent = 0;
-}
-
-/*
- * dir mods result
- * --- --- ------
- * Rerooting:
- *
- * (none) :R=dev: dev:
- * devd: :R=dev: devd:
- * devd:[dir] :R=dev: devd:[dir]
- * [.dir] :R=dev: dev:[dir] questionable
- * [dir] :R=dev: dev:[dir]
- *
- * (none) :R=[rdir] [rdir] questionable
- * devd: :R=[rdir] devd:
- * devd:[dir] :R=[rdir] devd:[dir]
- * [.dir] :R=[rdir] [rdir.dir] questionable
- * [dir] :R=[rdir] [rdir]
- *
- * (none) :R=dev:[root] dev:[root]
- * devd: :R=dev:[root] devd:
- * devd:[dir] :R=dev:[root] devd:[dir]
- * [.dir] :R=dev:[root] dev:[root.dir]
- * [dir] :R=dev:[root] [dir]
- *
- * Climbing to parent:
- *
- */
-
-# define DIR_EMPTY 0 /* empty string */
-# define DIR_DEV 1 /* dev: */
-# define DIR_DEVDIR 2 /* dev:[dir] */
-# define DIR_DOTDIR 3 /* [.dir] */
-# define DIR_DASHDIR 4 /* [-] or [-.dir] */
-# define DIR_ABSDIR 5 /* [dir] */
-# define DIR_ROOT 6 /* [000000] or dev:[000000] */
-
-# define G_DIR 0 /* take just dir */
-# define G_ROOT 1 /* take just root */
-# define G_VAD 2 /* root's dev: + [abs] */
-# define G_DRD 3 /* root's dev:[dir] + [.rel] */
-# define G_VRD 4 /* root's dev: + [.rel] made [abs] */
-# define G_DDD 5 /* root's dev:[dir] + . + [dir] */
-
-static int grid[7][7] = {
-
-/* root/dir EMPTY DEV DEVDIR DOTDIR DASH, ABSDIR ROOT */
-/* EMPTY */ G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR, G_DIR,
-/* DEV */ G_ROOT, G_DIR, G_DIR, G_VRD, G_VAD, G_VAD, G_VAD,
-/* DEVDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_VAD, G_VAD, G_VAD,
-/* DOTDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
-/* DASHDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DDD, G_DIR, G_DIR,
-/* ABSDIR */ G_ROOT, G_DIR, G_DIR, G_DRD, G_DIR, G_DIR, G_DIR,
-/* ROOT */ G_ROOT, G_DIR, G_DIR, G_VRD, G_DIR, G_DIR, G_DIR,
-
-};
-
-struct dirinf
-{
- int flags;
-
- struct
- {
- char * ptr;
- int len;
- } dev, dir;
-};
-
-static char * strnchr( char * buf, int c, int len )
-{
- while ( len-- )
- if ( *buf && ( *buf++ == c ) )
- return buf - 1;
- return 0;
-}
-
-
-static void dir_flags( char * buf, int len, struct dirinf * i )
-{
- char * p;
-
- if ( !buf || !len )
- {
- i->flags = DIR_EMPTY;
- i->dev.ptr =
- i->dir.ptr = 0;
- i->dev.len =
- i->dir.len = 0;
- }
- else if ( p = strnchr( buf, ':', len ) )
- {
- i->dev.ptr = buf;
- i->dev.len = p + 1 - buf;
- i->dir.ptr = buf + i->dev.len;
- i->dir.len = len - i->dev.len;
- i->flags = i->dir.len && *i->dir.ptr == '[' ? DIR_DEVDIR : DIR_DEV;
- }
- else
- {
- i->dev.ptr = buf;
- i->dev.len = 0;
- i->dir.ptr = buf;
- i->dir.len = len;
-
- if ( ( *buf == '[' ) && ( buf[1] == ']' ) )
- i->flags = DIR_EMPTY;
- else if ( ( *buf == '[' ) && ( buf[1] == '.' ) )
- i->flags = DIR_DOTDIR;
- else if ( ( *buf == '[' ) && ( buf[1] == '-' ) )
- i->flags = DIR_DASHDIR;
- else
- i->flags = DIR_ABSDIR;
- }
-
- /* But if its rooted in any way. */
-
- if ( ( i->dir.len == 8 ) && !strncmp( i->dir.ptr, "[000000]", 8 ) )
- i->flags = DIR_ROOT;
-}
-
-
-/*
- * path_build() - build a filename given dir/base/suffix/member
- */
-
-void path_build( PATHNAME * f, string * file, int binding )
-{
- struct dirinf root;
- struct dirinf dir;
- int g;
-
- file_build1( f, file );
-
- /* Get info on root and dir for combining. */
- dir_flags( f->f_root.ptr, f->f_root.len, &root );
- dir_flags( f->f_dir.ptr, f->f_dir.len, &dir );
-
- /* Combine. */
- switch ( g = grid[ root.flags ][ dir.flags ] )
- {
- case G_DIR:
- /* take dir */
- string_append_range( file, f->f_dir.ptr, f->f_dir.ptr + f->f_dir.len );
- break;
-
- case G_ROOT:
- /* take root */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
- break;
-
- case G_VAD:
- /* root's dev + abs directory */
- string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
- string_append_range( file, dir.dir.ptr, dir.dir.ptr + dir.dir.len );
- break;
-
- case G_DRD:
- case G_DDD:
- /* root's dev:[dir] + rel directory */
- string_append_range( file, f->f_root.ptr, f->f_root.ptr + f->f_root.len );
-
- /* sanity checks: root ends with ] */
-
- if ( file->value[file->size - 1] == ']' )
- string_pop_back( file );
-
- /* Add . if separating two -'s */
-
- if ( g == G_DDD )
- string_push_back( file, '.' );
-
- /* skip [ of dir */
- string_append_range( file, dir.dir.ptr + 1, dir.dir.ptr + 1 + dir.dir.len - 1 );
- break;
-
- case G_VRD:
- /* root's dev + rel directory made abs */
- string_append_range( file, root.dev.ptr, root.dev.ptr + root.dev.len );
- string_push_back( file, '[' );
- /* skip [. of rel dir */
- string_append_range( file, dir.dir.ptr + 2, dir.dir.ptr + 2 + dir.dir.len - 2 );
- break;
- }
-
-# ifdef DEBUG
- if ( DEBUG_SEARCH && ( root.flags || dir.flags ) )
- printf( "%d x %d = %d (%s)\n", root.flags, dir.flags,
- grid[ root.flags ][ dir.flags ], file->value );
-# endif
-
- /*
- * Now do the special :P modifier when no file was present.
- * (none) (none)
- * [dir1.dir2] [dir1]
- * [dir] [000000]
- * [.dir] (none)
- * [] []
- */
-
- if ( ( file->value[ file->size - 1 ] == ']' ) && f->parent )
- {
- char * p = file->value + file->size;
- while ( p-- > file->value )
- {
- if ( *p == '.' )
- {
- /* If we've truncated everything and left with '[',
- return empty string. */
- if ( p == file->value + 1 )
- string_truncate( file, 0 );
- else
- {
- string_truncate( file, p - file->value );
- string_push_back( file, ']' );
- }
- break;
- }
-
- if ( *p == '-' )
- {
- /* handle .- or - */
- if ( ( p > file->value ) && ( p[ -1 ] == '.' ) )
- --p;
-
- *p++ = ']';
- break;
- }
-
- if ( *p == '[' )
- {
- if ( p[ 1 ] == ']' )
- {
- /* CONSIDER: I don't see any use of this code. We immediately
- break, and 'p' is a local variable. */
- p += 2;
- }
- else
- {
- string_truncate( file, p - file->value );
- string_append( file, "[000000]" );
- }
- break;
- }
- }
- }
-
- /* Now copy the file pieces. */
- if ( f->f_base.len )
- {
- string_append_range( file, f->f_base.ptr, f->f_base.ptr + f->f_base.len );
- }
-
- /* If there is no suffix, we append a "." onto all generated names. This
- * keeps VMS from appending its own (wrong) idea of what the suffix should
- * be.
- */
- if ( f->f_suffix.len )
- string_append_range( file, f->f_suffix.ptr, f->f_suffix.ptr + f->f_suffix.len );
- else if ( binding && f->f_base.len )
- string_push_back( file, '.' );
-
- 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, ')' );
- }
-
-# ifdef DEBUG
- if ( DEBUG_SEARCH )
- printf( "built %.*s + %.*s / %.*s suf %.*s mem %.*s -> %s\n",
- f->f_root.len, f->f_root.ptr,
- f->f_dir.len, f->f_dir.ptr,
- f->f_base.len, f->f_base.ptr,
- f->f_suffix.len, f->f_suffix.ptr,
- f->f_member.len, f->f_member.ptr,
- file->value );
-# endif
-}
-
-
-/*
- * path_parent() - make a PATHNAME point to its parent dir
- */
-
-void path_parent( PATHNAME * f )
-{
- if ( f->f_base.len )
- {
- 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;
- }
- else
- {
- f->parent = 1;
- }
-}
-
-# endif /* VMS */
diff --git a/tools/build/v2/engine/pwd.c b/tools/build/v2/engine/pwd.c
index 90c8eb175d..93d8126032 100644
--- a/tools/build/v2/engine/pwd.c
+++ b/tools/build/v2/engine/pwd.c
@@ -4,7 +4,7 @@
#include "jam.h"
#include "lists.h"
-#include "newstr.h"
+#include "object.h"
#include "pathsys.h"
#include "mem.h"
@@ -29,7 +29,7 @@
/* The current directory can't change in bjam, so optimize this to cache
** the result.
*/
-static char * pwd_result = NULL;
+static OBJECT * pwd_result = NULL;
LIST*
@@ -46,9 +46,11 @@ pwd(void)
if (result_buffer)
{
#ifdef NT
- pwd_result = short_path_to_long_path(result_buffer);
+ OBJECT * result = object_new(result_buffer);
+ pwd_result = short_path_to_long_path(result);
+ object_free( result );
#else
- pwd_result = newstr(result_buffer);
+ pwd_result = object_new(result_buffer);
#endif
}
buffer_size *= 2;
@@ -62,5 +64,13 @@ pwd(void)
return L0;
}
}
- return list_new(L0, pwd_result);
+ return list_new( object_copy( pwd_result ) );
+}
+
+void pwd_done( void )
+{
+ if( pwd_result )
+ {
+ object_free( pwd_result );
+ }
}
diff --git a/tools/build/v2/engine/pwd.h b/tools/build/v2/engine/pwd.h
index 37cb531e4f..e6ed268bb2 100644
--- a/tools/build/v2/engine/pwd.h
+++ b/tools/build/v2/engine/pwd.h
@@ -5,6 +5,7 @@
#ifndef PWD_H
#define PWD_H
-LIST* pwd(void);
+LIST * pwd( void );
+void pwd_done( void );
#endif
diff --git a/tools/build/v2/engine/regexp.c b/tools/build/v2/engine/regexp.c
index 30197a2feb..b51b85b09c 100644
--- a/tools/build/v2/engine/regexp.c
+++ b/tools/build/v2/engine/regexp.c
@@ -152,7 +152,7 @@
* Utility definitions.
*/
#ifndef CHARBITS
-#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#define UCHARAT(p) ((int)*(const unsigned char *)(p))
#else
#define UCHARAT(p) ((int)*(p)&CHARBITS)
#endif
@@ -213,7 +213,7 @@ STATIC int strcspn();
* of the structure of the compiled regexp.
*/
regexp *
-regcomp( char *exp )
+regcomp( const char *exp )
{
register regexp *r;
register char *scan;
@@ -770,15 +770,15 @@ regoptail(
/*
* Global work variables for regexec().
*/
-static char *reginput; /* String-input pointer. */
-static char *regbol; /* Beginning of input, for ^ check. */
-static char **regstartp; /* Pointer to startp array. */
-static char **regendp; /* Ditto for endp. */
+static const char *reginput; /* String-input pointer. */
+static const char *regbol; /* Beginning of input, for ^ check. */
+static const char **regstartp; /* Pointer to startp array. */
+static const char **regendp; /* Ditto for endp. */
/*
* Forwards.
*/
-STATIC int regtry( regexp *prog, char *string );
+STATIC int regtry( regexp *prog, const char *string );
STATIC int regmatch( char *prog );
STATIC int regrepeat( char *p );
@@ -794,7 +794,7 @@ STATIC char *regprop();
int
regexec(
register regexp *prog,
- register char *string )
+ register const char *string )
{
register char *s;
@@ -859,11 +859,11 @@ regexec(
static int /* 0 failure, 1 success */
regtry(
regexp *prog,
- char *string )
+ const char *string )
{
register int i;
- register char * * sp;
- register char * * ep;
+ register const char * * sp;
+ register const char * * ep;
reginput = string;
regstartp = prog->startp;
@@ -982,7 +982,7 @@ regmatch( char * prog )
case OPEN+8:
case OPEN+9: {
register int no;
- register char *save;
+ register const char *save;
no = OP(scan) - OPEN;
save = reginput;
@@ -1010,7 +1010,7 @@ regmatch( char * prog )
case CLOSE+8:
case CLOSE+9: {
register int no;
- register char *save;
+ register const char *save;
no = OP(scan) - CLOSE;
save = reginput;
@@ -1029,7 +1029,7 @@ regmatch( char * prog )
}
break;
case BRANCH: {
- register char *save;
+ register const char *save;
if (OP(next) != BRANCH) /* No choice. */
next = OPERAND(scan); /* Avoid recursion. */
@@ -1050,7 +1050,7 @@ regmatch( char * prog )
case PLUS: {
register char nextch;
register int no;
- register char *save;
+ register const char *save;
register int min;
/*
@@ -1102,7 +1102,7 @@ static int
regrepeat( char *p )
{
register int count = 0;
- register char *scan;
+ register const char *scan;
register char *opnd;
scan = reginput;
diff --git a/tools/build/v2/engine/regexp.h b/tools/build/v2/engine/regexp.h
index 9d4604f60a..fccfb7dff8 100644
--- a/tools/build/v2/engine/regexp.h
+++ b/tools/build/v2/engine/regexp.h
@@ -9,8 +9,8 @@
#define NSUBEXP 10
typedef struct regexp {
- char *startp[NSUBEXP];
- char *endp[NSUBEXP];
+ const char *startp[NSUBEXP];
+ const char *endp[NSUBEXP];
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
@@ -18,9 +18,9 @@ typedef struct regexp {
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
-regexp *regcomp( char *exp );
-int regexec( regexp *prog, char *string );
-void regerror( char *s );
+regexp *regcomp( const char *exp );
+int regexec( regexp *prog, const char *string );
+void regerror( const char *s );
/*
* The first byte of the regexp internal "program" is actually this magic
diff --git a/tools/build/v2/engine/rules.c b/tools/build/v2/engine/rules.c
index a0be1d3400..b9ff6191f5 100644
--- a/tools/build/v2/engine/rules.c
+++ b/tools/build/v2/engine/rules.c
@@ -9,7 +9,7 @@
# include "parse.h"
# include "variable.h"
# include "rules.h"
-# include "newstr.h"
+# include "object.h"
# include "hash.h"
# include "modules.h"
# include "search.h"
@@ -45,19 +45,10 @@
*/
static void set_rule_actions( RULE *, rule_actions * );
-static void set_rule_body ( RULE *, argument_list *, PARSE * procedure );
+static void set_rule_body ( RULE *, FUNCTION * procedure );
static struct hash * targethash = 0;
-struct _located_target
-{
- char * file_name;
- TARGET * target;
-};
-typedef struct _located_target LOCATED_TARGET ;
-
-static struct hash * located_targets = 0;
-
/*
* target_include() - adds the 'included' TARGET to the list of targets included
@@ -83,25 +74,20 @@ void target_include( TARGET * including, TARGET * included )
* target_module.
*/
-static RULE * enter_rule( char * rulename, module_t * target_module )
+static RULE * enter_rule( OBJECT * rulename, module_t * target_module )
{
- RULE rule;
- RULE * r = &rule;
+ int found;
+ RULE * r;
- r->name = rulename;
-
- if ( hashenter( demand_rules( target_module ), (HASHDATA * *)&r ) )
+ r = (RULE *)hash_insert( demand_rules(target_module), rulename, &found );
+ if ( !found )
{
- r->name = newstr( rulename ); /* never freed */
- r->procedure = (PARSE *)0;
+ r->name = object_copy( rulename );
+ r->procedure = 0;
r->module = 0;
r->actions = 0;
- r->arguments = 0;
r->exported = 0;
r->module = target_module;
-#ifdef HAVE_PYTHON
- r->python_function = 0;
-#endif
}
return r;
}
@@ -116,14 +102,14 @@ static RULE * enter_rule( char * rulename, module_t * target_module )
static RULE * define_rule
(
module_t * src_module,
- char * rulename,
+ 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 */
{
- set_rule_body( r, 0, 0 );
+ set_rule_body( r, 0 );
set_rule_actions( r, 0 );
r->module = src_module; /* r will be executed in the source module */
}
@@ -133,13 +119,11 @@ static RULE * define_rule
void rule_free( RULE * r )
{
- freestr( r->name );
- r->name = "";
- parse_free( r->procedure );
+ object_free( r->name );
+ r->name = 0;
+ if ( r->procedure )
+ function_free( r->procedure );
r->procedure = 0;
- if ( r->arguments )
- args_free( r->arguments );
- r->arguments = 0;
if ( r->actions )
actions_free( r->actions );
r->actions = 0;
@@ -150,25 +134,20 @@ void rule_free( RULE * r )
* bindtarget() - return pointer to TARGET, creating it if necessary.
*/
-TARGET * bindtarget( char const * target_name )
+TARGET * bindtarget( OBJECT * target_name )
{
- TARGET target;
- TARGET * t = &target;
+ int found;
+ TARGET * t;
if ( !targethash )
targethash = hashinit( sizeof( TARGET ), "targets" );
- /* Perforce added const everywhere. No time to merge that change. */
-#ifdef NT
- target_name = short_path_to_long_path( (char *)target_name );
-#endif
- t->name = (char *)target_name;
-
- if ( hashenter( targethash, (HASHDATA * *)&t ) )
+ t = (TARGET *)hash_insert( targethash, target_name, &found );
+ if ( !found )
{
memset( (char *)t, '\0', sizeof( *t ) );
- t->name = newstr( (char *)target_name ); /* never freed */
- t->boundname = t->name; /* default for T_FLAG_NOTFILE */
+ t->name = object_copy( target_name );
+ t->boundname = object_copy( t->name ); /* default for T_FLAG_NOTFILE */
}
return t;
@@ -184,14 +163,15 @@ static void bind_explicitly_located_target( void * xtarget, void * data )
SETTINGS * s = t->settings;
for ( ; s ; s = s->next )
{
- if ( strcmp( s->symbol, "LOCATE" ) == 0 )
+ if ( strcmp( object_str( s->symbol ), "LOCATE" ) == 0 )
{
- pushsettings( t->settings );
+ 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( t->settings );
+ popsettings( root_module(), t->settings );
break;
}
}
@@ -206,81 +186,6 @@ void bind_explicitly_located_targets()
}
-/* TODO: It is probably not a good idea to use functions in other modules like
- this. */
-void call_bind_rule( char * target, char * boundname );
-
-
-TARGET * search_for_target ( char * name, LIST * search_path )
-{
- PATHNAME f[1];
- string buf[1];
- LOCATED_TARGET lt;
- LOCATED_TARGET * lta = &lt;
- time_t time;
- int found = 0;
- TARGET * result;
-
- string_new( buf );
-
- path_parse( name, f );
-
- f->f_grist.ptr = 0;
- f->f_grist.len = 0;
-
- while ( search_path )
- {
- f->f_root.ptr = search_path->string;
- f->f_root.len = strlen( search_path->string );
-
- string_truncate( buf, 0 );
- path_build( f, buf, 1 );
-
- lt.file_name = buf->value ;
-
- if ( !located_targets )
- located_targets = hashinit( sizeof(LOCATED_TARGET),
- "located targets" );
-
- if ( hashcheck( located_targets, (HASHDATA * *)&lta ) )
- {
- return lta->target;
- }
-
- timestamp( buf->value, &time );
- if ( time )
- {
- found = 1;
- break;
- }
-
- search_path = list_next( search_path );
- }
-
- if ( !found )
- {
- f->f_root.ptr = 0;
- f->f_root.len = 0;
-
- string_truncate( buf, 0 );
- path_build( f, buf, 1 );
-
- timestamp( buf->value, &time );
- }
-
- result = bindtarget( name );
- result->boundname = newstr( buf->value );
- result->time = time;
- result->binding = time ? T_BIND_EXISTS : T_BIND_MISSING;
-
- call_bind_rule( result->name, result->boundname );
-
- string_free( buf );
-
- return result;
-}
-
-
/*
* copytarget() - make a new target with the old target's name.
*
@@ -291,8 +196,8 @@ TARGET * copytarget( const TARGET * ot )
{
TARGET * t = (TARGET *)BJAM_MALLOC( sizeof( *t ) );
memset( (char *)t, '\0', sizeof( *t ) );
- t->name = copystr( ot->name );
- t->boundname = t->name;
+ t->name = object_copy( ot->name );
+ t->boundname = object_copy( t->name );
t->flags |= T_FLAG_NOTFILE | T_FLAG_INTERNAL;
@@ -304,7 +209,7 @@ TARGET * copytarget( const TARGET * ot )
* touch_target() - mark a target to simulate being new.
*/
-void touch_target( char * t )
+void touch_target( OBJECT * t )
{
bindtarget( t )->flags |= T_FLAG_TOUCHED;
}
@@ -320,8 +225,9 @@ void touch_target( char * t )
TARGETS * targetlist( TARGETS * chain, LIST * target_names )
{
- for ( ; target_names; target_names = list_next( target_names ) )
- chain = targetentry( chain, bindtarget( target_names->string ) );
+ LISTITER iter = list_begin( target_names ), end = list_end( target_names );
+ for ( ; iter != end; iter = list_next( iter ) )
+ chain = targetentry( chain, bindtarget( list_item( iter ) ) );
return chain;
}
@@ -368,6 +274,21 @@ TARGETS * targetchain( TARGETS * chain, TARGETS * targets )
}
/*
+ * action_free - decrement the ACTIONs refrence count
+ * and (maybe) free it.
+ */
+
+void action_free ( ACTION * action )
+{
+ if ( --action->refs == 0 )
+ {
+ freetargets( action->targets );
+ freetargets( action->sources );
+ BJAM_FREE( action );
+ }
+}
+
+/*
* actionlist() - append to an ACTION chain.
*/
@@ -377,6 +298,7 @@ ACTIONS * actionlist( ACTIONS * chain, ACTION * action )
actions->action = action;
+ ++action->refs;
if ( !chain ) chain = actions;
else chain->tail->next = actions;
chain->tail = actions;
@@ -397,13 +319,13 @@ static SETTINGS * settings_freelist;
* the head of the settings chain.
*/
-SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
+SETTINGS * addsettings( SETTINGS * head, int flag, OBJECT * symbol, LIST * value )
{
SETTINGS * v;
/* Look for previous settings. */
for ( v = head; v; v = v->next )
- if ( !strcmp( v->symbol, symbol ) )
+ if ( object_equal( v->symbol, symbol ) )
break;
/* If not previously set, alloc a new. */
@@ -418,10 +340,9 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
else
v = (SETTINGS *)BJAM_MALLOC( sizeof( *v ) );
- v->symbol = newstr( symbol );
+ v->symbol = object_copy( symbol );
v->value = value;
v->next = head;
- v->multiple = 0;
head = v;
}
else if ( flag == VAR_APPEND )
@@ -445,10 +366,10 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value )
* pushsettings() - set all target specific variables.
*/
-void pushsettings( SETTINGS * v )
+void pushsettings( struct module_t * module, SETTINGS * v )
{
for ( ; v; v = v->next )
- v->value = var_swap( v->symbol, v->value );
+ v->value = var_swap( module, v->symbol, v->value );
}
@@ -456,9 +377,9 @@ void pushsettings( SETTINGS * v )
* popsettings() - reset target specific variables to their pre-push values.
*/
-void popsettings( SETTINGS * v )
+void popsettings( struct module_t * module, SETTINGS * v )
{
- pushsettings( v ); /* just swap again */
+ pushsettings( module, v ); /* just swap again */
}
@@ -471,7 +392,7 @@ SETTINGS * copysettings( SETTINGS * head )
SETTINGS * copy = 0;
SETTINGS * v;
for ( v = head; v; v = v->next )
- copy = addsettings( copy, VAR_SET, v->symbol, list_copy( 0, v->value ) );
+ copy = addsettings( copy, VAR_SET, v->symbol, list_copy( v->value ) );
return copy;
}
@@ -500,6 +421,7 @@ void freeactions( ACTIONS * chain )
while ( chain )
{
ACTIONS * n = chain->next;
+ action_free( chain->action );
BJAM_FREE( chain );
chain = n;
}
@@ -515,7 +437,7 @@ void freesettings( SETTINGS * v )
while ( v )
{
SETTINGS * n = v->next;
- freestr( v->symbol );
+ object_free( v->symbol );
list_free( v->value );
v->next = settings_freelist;
settings_freelist = v;
@@ -527,10 +449,19 @@ void freesettings( SETTINGS * v )
static void freetarget( void * xt, void * data )
{
TARGET * t = (TARGET *)xt;
- if ( t->settings ) freesettings( t->settings );
- if ( t->depends ) freetargets ( t->depends );
- if ( t->includes ) freetarget ( t->includes, (void *)0 );
- if ( t->actions ) freeactions ( t->actions );
+ if ( t->name ) object_free ( t->name );
+ if ( t->boundname ) object_free ( t->boundname );
+ if ( t->settings ) freesettings( t->settings );
+ if ( t->depends ) freetargets ( t->depends );
+ 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 );
+ BJAM_FREE( t->includes );
+ }
}
@@ -540,8 +471,11 @@ static void freetarget( void * xt, void * data )
void rules_done()
{
- hashenumerate( targethash, freetarget, 0 );
- hashdone( targethash );
+ if ( targethash )
+ {
+ hashenumerate( targethash, freetarget, 0 );
+ hashdone( targethash );
+ }
while ( settings_freelist )
{
SETTINGS * n = settings_freelist->next;
@@ -552,43 +486,6 @@ void rules_done()
/*
- * args_new() - make a new reference-counted argument list.
- */
-
-argument_list * args_new()
-{
- argument_list * r = (argument_list *)BJAM_MALLOC( sizeof(argument_list) );
- r->reference_count = 0;
- lol_init( r->data );
- return r;
-}
-
-
-/*
- * args_refer() - add a new reference to the given argument list.
- */
-
-void args_refer( argument_list * a )
-{
- ++a->reference_count;
-}
-
-
-/*
- * args_free() - release a reference to the given argument list.
- */
-
-void args_free( argument_list * a )
-{
- if ( --a->reference_count <= 0 )
- {
- lol_free( a->data );
- BJAM_FREE( a );
- }
-}
-
-
-/*
* actions_refer() - add a new reference to the given actions.
*/
@@ -606,29 +503,22 @@ void actions_free( rule_actions * a )
{
if ( --a->reference_count <= 0 )
{
- freestr( a->command );
+ function_free( a->command );
list_free( a->bindlist );
BJAM_FREE( a );
}
}
-
/*
* set_rule_body() - set the argument list and procedure of the given rule.
*/
-static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure )
+static void set_rule_body( RULE * rule, FUNCTION * procedure )
{
- if ( args )
- args_refer( args );
- if ( rule->arguments )
- args_free( rule->arguments );
- rule->arguments = args;
-
if ( procedure )
- parse_refer( procedure );
+ function_refer( procedure );
if ( rule->procedure )
- parse_free( rule->procedure );
+ function_free( rule->procedure );
rule->procedure = procedure;
}
@@ -638,16 +528,20 @@ static void set_rule_body( RULE * rule, argument_list * args, PARSE * procedure
* global module.
*/
-static char * global_rule_name( RULE * r )
+static OBJECT * global_rule_name( RULE * r )
{
if ( r->module == root_module() )
- return r->name;
+ return object_copy( r->name );
{
char name[4096] = "";
- strncat( name, r->module->name, sizeof( name ) - 1 );
- strncat( name, r->name, sizeof( name ) - 1 );
- return newstr( name);
+ if ( r->module->name )
+ {
+ strncat( name, object_str( r->module->name ), sizeof( name ) - 1 );
+ strncat( name, ".", sizeof( name ) - 1 );
+ }
+ strncat( name, object_str( r->name ), sizeof( name ) - 1 );
+ return object_new( name );
}
}
@@ -663,9 +557,9 @@ static RULE * global_rule( RULE * r )
return r;
{
- char * name = global_rule_name( r );
+ OBJECT * name = global_rule_name( r );
RULE * result = define_rule( r->module, name, root_module() );
- freestr( name );
+ object_free( name );
return result;
}
}
@@ -677,19 +571,19 @@ static RULE * global_rule( RULE * r )
* exported to the global module as modulename.rulename.
*/
-RULE * new_rule_body( module_t * m, char * rulename, argument_list * args, PARSE * procedure, int exported )
+RULE * new_rule_body( module_t * m, OBJECT * rulename, FUNCTION * procedure, int exported )
{
RULE * local = define_rule( m, rulename, m );
local->exported = exported;
- set_rule_body( local, args, procedure );
+ set_rule_body( local, procedure );
/* Mark the procedure with the global rule name, regardless of whether the
* rule is exported. That gives us something reasonably identifiable that we
* can use, e.g. in profiling output. Only do this once, since this could be
* called multiple times with the same procedure.
*/
- if ( procedure->rulename == 0 )
- procedure->rulename = global_rule_name( local );
+ if ( function_rulename( procedure ) == 0 )
+ function_set_rulename( procedure, global_rule_name( local ) );
return local;
}
@@ -705,10 +599,11 @@ static void set_rule_actions( RULE * rule, rule_actions * actions )
}
-static rule_actions * actions_new( char * 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 ) );
- result->command = copystr( command );
+ function_refer( command );
+ result->command = command;
result->bindlist = bindlist;
result->flags = flags;
result->reference_count = 0;
@@ -716,7 +611,7 @@ static rule_actions * actions_new( char * command, LIST * bindlist, int flags )
}
-RULE * new_rule_actions( module_t * m, char * rulename, char * 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 );
@@ -733,32 +628,37 @@ RULE * new_rule_actions( module_t * m, char * rulename, char * command, LIST * b
* modules, look in module 'name1' for rule 'name2'.
*/
-RULE * lookup_rule( char * rulename, module_t * m, int local_only )
+RULE * lookup_rule( OBJECT * rulename, module_t * m, int local_only )
{
- RULE rule;
- RULE * r = &rule;
+ RULE * r;
RULE * result = 0;
module_t * original_module = m;
- r->name = rulename;
-
if ( m->class_module )
m = m->class_module;
- if ( m->rules && hashcheck( m->rules, (HASHDATA * *)&r ) )
+ if ( m->rules && ( r = (RULE *)hash_find( m->rules, rulename ) ) )
result = r;
else if ( !local_only && m->imported_modules )
{
/* Try splitting the name into module and rule. */
- char *p = strchr( r->name, '.' ) ;
+ char *p = strchr( object_str( rulename ), '.' ) ;
if ( p )
{
- *p = '\0';
+ 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.
*/
- if ( hashcheck( m->imported_modules, (HASHDATA * *)&r ) )
- result = lookup_rule( p + 1, bindmodule( rulename ), 1 );
- *p = '.';
+ 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 );
}
}
@@ -786,7 +686,7 @@ RULE * lookup_rule( char * rulename, module_t * m, int local_only )
}
-RULE * bindrule( char * rulename, module_t * m )
+RULE * bindrule( OBJECT * rulename, module_t * m )
{
RULE * result = lookup_rule( rulename, m, 0 );
if ( !result )
@@ -801,10 +701,24 @@ RULE * bindrule( char * rulename, module_t * m )
}
-RULE * import_rule( RULE * source, module_t * m, char * name )
+RULE * import_rule( RULE * source, module_t * m, OBJECT * name )
{
RULE * dest = define_rule( source->module, name, m );
- set_rule_body( dest, source->arguments, source->procedure );
+ set_rule_body( dest, source->procedure );
set_rule_actions( dest, source->actions );
return dest;
}
+
+
+void rule_localize( RULE * rule, module_t * m )
+{
+ rule->module = m;
+ if ( rule->procedure )
+ {
+ FUNCTION * procedure = function_unbind_variables( rule->procedure );
+ function_refer( procedure );
+ function_free( rule->procedure );
+ rule->procedure = procedure;
+ }
+}
+
diff --git a/tools/build/v2/engine/rules.h b/tools/build/v2/engine/rules.h
index 806a1469c0..823fbd1f55 100644
--- a/tools/build/v2/engine/rules.h
+++ b/tools/build/v2/engine/rules.h
@@ -15,7 +15,7 @@
#include "modules.h"
#include "jam.h"
-#include "parse.h"
+#include "function.h"
/*
@@ -52,20 +52,13 @@ typedef struct _settings SETTINGS ;
/* RULE - a generic jam rule, the product of RULE and ACTIONS. */
-/* A rule's argument list. */
-struct argument_list
-{
- int reference_count;
- LOL data[1];
-};
-
/* Build actions corresponding to a rule. */
struct rule_actions
{
- int reference_count;
- char * command; /* command string from ACTIONS */
- LIST * bindlist;
- int flags; /* modifiers on ACTIONS */
+ int reference_count;
+ FUNCTION * command; /* command string from ACTIONS */
+ LIST * bindlist;
+ int flags; /* modifiers on ACTIONS */
#define RULE_NEWSRCS 0x01 /* $(>) is updated sources only */
#define RULE_TOGETHER 0x02 /* combine actions on single target */
@@ -80,19 +73,14 @@ typedef struct argument_list argument_list;
struct _rule
{
- char * name;
- PARSE * procedure; /* parse tree from RULE */
- argument_list * arguments; /* argument checking info, or NULL for unchecked
- */
+ OBJECT * name;
+ FUNCTION * procedure;
rule_actions * actions; /* build actions, or NULL for no actions */
module_t * module; /* module in which this rule is executed */
int exported; /* nonzero if this rule is supposed to appear in
* the global module and be automatically
* imported into other modules
*/
-#ifdef HAVE_PYTHON
- PyObject * python_function;
-#endif
};
/* ACTIONS - a chain of ACTIONs. */
@@ -110,16 +98,19 @@ struct _action
TARGETS * targets;
TARGETS * sources; /* aka $(>) */
char running; /* has been started */
+#define A_INIT 0
+#define A_RUNNING_NOEXEC 1
+#define A_RUNNING 2
char status; /* see TARGET status */
+ int refs;
};
/* SETTINGS - variables to set when executing a TARGET's ACTIONS. */
struct _settings
{
SETTINGS * next;
- char * symbol; /* symbol name for var_set() */
+ OBJECT * symbol; /* symbol name for var_set() */
LIST * value; /* symbol value for var_set() */
- int multiple;
};
/* TARGETS - a chain of TARGETs. */
@@ -133,8 +124,8 @@ struct _targets
/* TARGET - an entity (e.g. a file) that can be built. */
struct _target
{
- char * name;
- char * boundname; /* if search() relocates target */
+ OBJECT * name;
+ OBJECT * boundname; /* if search() relocates target */
ACTIONS * actions; /* rules to execute, if any */
SETTINGS * settings; /* variables to define */
@@ -220,6 +211,7 @@ struct _target
#define T_MAKE_ACTIVE 2 /* make1(target) in make1b() */
#define T_MAKE_RUNNING 3 /* make1(target) running commands */
#define T_MAKE_DONE 4 /* make1(target) done */
+#define T_MAKE_NOEXEC_DONE 5 /* make1(target) done with -n in effect */
#ifdef OPT_SEMAPHORE
#define T_MAKE_SEMAPHORE 5 /* Special target type for semaphores */
@@ -235,44 +227,41 @@ struct _target
TARGETS * parents; /* used by make1() for completion */
char * cmds; /* type-punned command list */
- char * failed;
+ const char * failed;
};
/* Action related functions. */
+void action_free ( ACTION * );
ACTIONS * actionlist ( ACTIONS *, ACTION * );
void freeactions ( ACTIONS * );
-SETTINGS * addsettings ( SETTINGS *, int flag, char * symbol, LIST * value );
-void pushsettings ( SETTINGS * );
-void popsettings ( SETTINGS * );
+SETTINGS * addsettings ( SETTINGS *, int flag, OBJECT * symbol, LIST * value );
+void pushsettings ( struct module_t * module, SETTINGS * );
+void popsettings ( struct module_t * module, SETTINGS * );
SETTINGS * copysettings ( SETTINGS * );
void freesettings ( SETTINGS * );
void actions_refer( rule_actions * );
void actions_free ( rule_actions * );
-/* Argument list related functions. */
-void args_free ( argument_list * );
-argument_list * args_new ();
-void args_refer( argument_list * );
-
/* Rule related functions. */
-RULE * bindrule ( char * rulename, module_t * );
-RULE * import_rule ( RULE * source, module_t *, char * name );
-RULE * new_rule_body ( module_t *, char * rulename, argument_list *, PARSE * procedure, int exprt );
-RULE * new_rule_actions( module_t *, char * rulename, char * command, LIST * bindlist, int flags );
+RULE * bindrule ( OBJECT * rulename, module_t * );
+RULE * import_rule ( RULE * source, module_t *, OBJECT * name );
+void rule_localize ( RULE * rule, module_t * module );
+RULE * new_rule_body ( module_t *, OBJECT * rulename, FUNCTION * func, int exprt );
+RULE * new_rule_actions( module_t *, OBJECT * rulename, FUNCTION * command, LIST * bindlist, int flags );
void rule_free ( RULE * );
/* Target related functions. */
void bind_explicitly_located_targets();
-TARGET * bindtarget ( char const * target_name );
+TARGET * bindtarget ( OBJECT * target_name );
TARGET * copytarget ( TARGET const * t );
void freetargets ( TARGETS * );
-TARGET * search_for_target ( char * name, LIST * search_path );
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 ( char * t );
+void touch_target ( OBJECT * t );
+void clear_includes ( TARGET * );
/* Final module cleanup. */
void rules_done();
diff --git a/tools/build/v2/engine/scan.c b/tools/build/v2/engine/scan.c
index 11c44c0e21..915ec21f44 100644
--- a/tools/build/v2/engine/scan.c
+++ b/tools/build/v2/engine/scan.c
@@ -10,7 +10,8 @@
#include "scan.h"
#include "jamgram.h"
#include "jambase.h"
-#include "newstr.h"
+#include "object.h"
+#include "constants.h"
/*
* scan.c - the jam yacc scanner
@@ -41,7 +42,7 @@ struct include
char * string; /* pointer into current line */
char * * strings; /* for yyfparse() -- text to parse */
FILE * file; /* for yyfparse() -- file being read */
- char * fname; /* for yyfparse() -- file name */
+ OBJECT * fname; /* for yyfparse() -- file name */
int line; /* line counter for error messages */
char buf[ 512 ]; /* for yyfparse() -- line buffer */
};
@@ -67,7 +68,7 @@ void yymode( int n )
}
-void yyerror( char * s )
+void yyerror( const char * 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
@@ -82,7 +83,7 @@ void yyerror( char * s )
* TODO: Test the theory about when yylval and incp location information are
* the same and when they differ.
*/
- printf( "%s:%d: %s at %s\n", yylval.file, yylval.line, s, symdump( &yylval ) );
+ printf( "%s:%d: %s at %s\n", object_str( yylval.file ), yylval.line, s, symdump( &yylval ) );
++anyerrors;
}
@@ -93,7 +94,7 @@ int yyanyerrors()
}
-void yyfparse( char * s )
+void yyfparse( OBJECT * s )
{
struct include * i = (struct include *)BJAM_MALLOC( sizeof( *i ) );
@@ -101,13 +102,13 @@ void yyfparse( char * s )
i->string = "";
i->strings = 0;
i->file = 0;
- i->fname = copystr( s );
+ i->fname = object_copy( s );
i->line = 0;
i->next = incp;
incp = i;
/* If the filename is "+", it means use the internal jambase. */
- if ( !strcmp( s, "+" ) )
+ if ( !strcmp( object_str( s ), "+" ) )
i->strings = jambase;
}
@@ -151,8 +152,8 @@ int yyline()
if ( !i->file )
{
FILE * f = stdin;
- if ( strcmp( i->fname, "-" ) && !( f = fopen( i->fname, "r" ) ) )
- perror( i->fname );
+ if ( strcmp( object_str( i->fname ), "-" ) && !( f = fopen( object_str( i->fname ), "r" ) ) )
+ perror( object_str( i->fname ) );
i->file = f;
}
@@ -174,7 +175,7 @@ int yyline()
/* Close file, free name. */
if ( i->file && ( i->file != stdin ) )
fclose( i->file );
- freestr( i->fname );
+ object_free( i->fname );
BJAM_FREE( (char *)i );
return EOF;
@@ -252,7 +253,7 @@ int yylex()
*b = 0;
yylval.type = STRING;
- yylval.string = newstr( buf );
+ yylval.string = object_new( buf );
yylval.file = incp->fname;
yylval.line = incp->line;
}
@@ -361,12 +362,12 @@ int yylex()
if ( ( *buf == *k->word ) && !strcmp( k->word, buf ) )
{
yylval.type = k->type;
- yylval.string = k->word; /* used by symdump */
+ yylval.keyword = k->word; /* used by symdump */
break;
}
if ( yylval.type == ARG )
- yylval.string = newstr( buf );
+ yylval.string = object_new( buf );
}
if ( DEBUG_SCAN )
@@ -388,11 +389,11 @@ static char * symdump( YYSTYPE * s )
static char buf[ BIGGEST_TOKEN + 20 ];
switch ( s->type )
{
- case EOF : sprintf( buf, "EOF" ); break;
- case 0 : sprintf( buf, "unknown symbol %s", s->string ); break;
- case ARG : sprintf( buf, "argument %s" , s->string ); break;
- case STRING: sprintf( buf, "string \"%s\"" , s->string ); break;
- default : sprintf( buf, "keyword %s" , s->string ); 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;
}
return buf;
}
@@ -403,7 +404,7 @@ static char * symdump( YYSTYPE * s )
* transitions that produce a parse.
*/
-void yyinput_stream( char * * name, int * line )
+void yyinput_stream( OBJECT * * name, int * line )
{
if ( incp )
{
@@ -412,7 +413,7 @@ void yyinput_stream( char * * name, int * line )
}
else
{
- *name = "(builtin)";
+ *name = constant_builtin;
*line = -1;
}
}
diff --git a/tools/build/v2/engine/scan.h b/tools/build/v2/engine/scan.h
index 3fad1c24cf..b672d00262 100644
--- a/tools/build/v2/engine/scan.h
+++ b/tools/build/v2/engine/scan.h
@@ -31,25 +31,26 @@
typedef struct _YYSTYPE
{
- int type;
- char * string;
- PARSE * parse;
- LIST * list;
- int number;
- char * file;
- int line;
+ int type;
+ OBJECT * string;
+ PARSE * parse;
+ LIST * list;
+ int number;
+ OBJECT * file;
+ int line;
+ const char * keyword;
} YYSTYPE;
extern YYSTYPE yylval;
void yymode( int n );
-void yyerror( char * s );
+void yyerror( const char * s );
int yyanyerrors();
-void yyfparse( char * s );
+void yyfparse( OBJECT * s );
int yyline();
int yylex();
int yyparse();
-void yyinput_stream( char * * name, int * line );
+void yyinput_stream( OBJECT * * name, int * line );
# define SCAN_NORMAL 0 /* normal parsing */
# define SCAN_STRING 1 /* look only for matching } */
diff --git a/tools/build/v2/engine/search.c b/tools/build/v2/engine/search.c
index 6c23d97a14..e3d287a679 100644
--- a/tools/build/v2/engine/search.c
+++ b/tools/build/v2/engine/search.c
@@ -16,7 +16,7 @@
#include "timestamp.h"
#include "pathsys.h"
#include "variable.h"
-#include "newstr.h"
+#include "object.h"
#include "compile.h"
#include "strings.h"
#include "hash.h"
@@ -26,8 +26,8 @@
typedef struct _binding
{
- char * binding;
- char * target;
+ OBJECT * binding;
+ OBJECT * target;
} BINDING;
static struct hash *explicit_bindings = 0;
@@ -35,22 +35,15 @@ static struct hash *explicit_bindings = 0;
void call_bind_rule
(
- char * target_,
- char * boundname_
+ OBJECT * target_,
+ OBJECT * boundname_
)
{
- LIST * bind_rule = var_get( "BINDRULE" );
- if ( bind_rule )
+ LIST * bind_rule = var_get( root_module(), constant_BINDRULE );
+ if ( !list_empty( bind_rule ) )
{
- /* No guarantee that the target is an allocated string, so be on the
- * safe side.
- */
- char * target = copystr( target_ );
-
- /* Likewise, do not rely on implementation details of newstr.c: allocate
- * a copy of boundname.
- */
- char * boundname = copystr( boundname_ );
+ OBJECT * target = object_copy( target_ );
+ OBJECT * boundname = object_copy( boundname_ );
if ( boundname && target )
{
/* Prepare the argument list. */
@@ -58,11 +51,11 @@ void call_bind_rule
frame_init( frame );
/* First argument is the target name. */
- lol_add( frame->args, list_new( L0, target ) );
+ lol_add( frame->args, list_new( target ) );
- lol_add( frame->args, list_new( L0, boundname ) );
+ lol_add( frame->args, list_new( boundname ) );
if ( lol_get( frame->args, 1 ) )
- evaluate_rule( bind_rule->string, frame );
+ list_free( evaluate_rule( list_front( bind_rule ), frame ) );
/* Clean up */
frame_free( frame );
@@ -70,9 +63,9 @@ void call_bind_rule
else
{
if ( boundname )
- freestr( boundname );
+ object_free( boundname );
if ( target )
- freestr( target );
+ object_free( target );
}
}
}
@@ -93,21 +86,21 @@ void call_bind_rule
* the third argument.
*/
-char *
+OBJECT *
search(
- char *target,
+ OBJECT * target,
time_t *time,
- char **another_target,
+ OBJECT * * another_target,
int file
)
{
PATHNAME f[1];
- LIST *varlist;
- string buf[1];
- int found = 0;
+ LIST * varlist;
+ string buf[1];
+ int found = 0;
/* Will be set to 1 if target location is specified via LOCATE. */
- int explicitly_located = 0;
- char *boundname = 0;
+ int explicitly_located = 0;
+ OBJECT * boundname = 0;
if ( another_target )
*another_target = 0;
@@ -119,55 +112,64 @@ search(
string_new( buf );
/* Parse the filename */
- path_parse( target, f );
+ path_parse( object_str( target ), f );
f->f_grist.ptr = 0;
f->f_grist.len = 0;
- if ( ( varlist = var_get( "LOCATE" ) ) )
- {
- f->f_root.ptr = varlist->string;
- f->f_root.len = strlen( varlist->string );
+ varlist = var_get( root_module(), constant_LOCATE );
+ if ( !list_empty( varlist ) )
+ {
+ OBJECT * key;
+ f->f_root.ptr = object_str( list_front( varlist ) );
+ f->f_root.len = strlen( object_str( list_front( varlist ) ) );
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "locate %s: %s\n", target, buf->value );
+ printf( "locate %s: %s\n", object_str( target ), buf->value );
explicitly_located = 1;
- timestamp( buf->value, time );
+ key = object_new( buf->value );
+ timestamp( key, time );
+ object_free( key );
found = 1;
}
- else if ( ( varlist = var_get( "SEARCH" ) ) )
+ else if ( varlist = var_get( root_module(), constant_SEARCH ), !list_empty( varlist ) )
{
- while ( varlist )
+ LISTITER iter = list_begin( varlist ), end = list_end( varlist );
+ for ( ; iter != end; iter = list_next( iter ) )
{
- BINDING b, *ba = &b;
+ BINDING * ba;
file_info_t *ff;
+ OBJECT * key;
+ OBJECT * test_path;
- f->f_root.ptr = varlist->string;
- f->f_root.len = strlen( varlist->string );
+ f->f_root.ptr = object_str( list_item( iter ) );
+ f->f_root.len = strlen( object_str( list_item( iter ) ) );
string_truncate( buf, 0 );
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "search %s: %s\n", target, buf->value );
-
- ff = file_query(buf->value);
- timestamp( buf->value, time );
+ printf( "search %s: %s\n", object_str( target ), buf->value );
- b.binding = buf->value;
+ test_path = object_new( buf->value );
+ key = path_as_key( test_path );
+ object_free( test_path );
+ ff = file_query( key );
+ timestamp( key, time );
- if ( hashcheck( explicit_bindings, (HASHDATA**)&ba ) )
+ if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
{
if ( DEBUG_SEARCH )
printf(" search %s: found explicitly located target %s\n",
- target, 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 )
@@ -175,11 +177,11 @@ search(
if ( !file || ff->is_file )
{
found = 1;
+ object_free( key );
break;
}
}
-
- varlist = list_next( varlist );
+ object_free( key );
}
}
@@ -188,6 +190,7 @@ search(
/* 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;
@@ -196,24 +199,34 @@ search(
path_build( f, buf, 1 );
if ( DEBUG_SEARCH )
- printf( "search %s: %s\n", target, buf->value );
+ printf( "search %s: %s\n", object_str( target ), buf->value );
- timestamp( buf->value, time );
+ key = object_new( buf->value );
+ timestamp( key, time );
+ object_free( key );
}
- boundname = newstr( buf->value );
+ boundname = object_new( buf->value );
string_free( buf );
if ( explicitly_located )
{
- BINDING b;
- BINDING * ba = &b;
- b.binding = boundname;
- b.target = target;
+ 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. */
- hashenter( explicit_bindings, (HASHDATA * *)&ba );
+ 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 */
@@ -221,3 +234,19 @@ search(
return boundname;
}
+
+
+static void free_binding( void * xbinding, void * data )
+{
+ BINDING * binding = (BINDING *)xbinding;
+ object_free( binding->binding );
+}
+
+void search_done( void )
+{
+ if ( explicit_bindings )
+ {
+ hashenumerate( explicit_bindings, free_binding, (void *)0 );
+ hashdone( explicit_bindings );
+ }
+}
diff --git a/tools/build/v2/engine/search.h b/tools/build/v2/engine/search.h
index c364cac03b..0b6583996b 100644
--- a/tools/build/v2/engine/search.h
+++ b/tools/build/v2/engine/search.h
@@ -8,4 +8,13 @@
* search.h - find a target along $(SEARCH) or $(LOCATE)
*/
-char *search( char *target, time_t *time, char **another_target, int file );
+#ifndef SEARCH_SW20111118_H
+#define SEARCH_SW20111118_H
+
+#include "object.h"
+#include <time.h>
+
+OBJECT * search( OBJECT * target, time_t * time, OBJECT * * another_target, int file );
+void search_done( void );
+
+#endif
diff --git a/tools/build/v2/engine/subst.c b/tools/build/v2/engine/subst.c
index 75524ecc12..156670f1e9 100644
--- a/tools/build/v2/engine/subst.c
+++ b/tools/build/v2/engine/subst.c
@@ -3,62 +3,64 @@
#include "regexp.h"
#include "hash.h"
-#include "newstr.h"
+#include "object.h"
#include "lists.h"
-#include "parse.h"
#include "compile.h"
#include "frames.h"
+#include "builtins.h"
struct regex_entry
{
- const char* pattern;
+ OBJECT* pattern;
regexp* regex;
};
typedef struct regex_entry regex_entry;
static struct hash* regex_hash;
-regexp* regex_compile( const char* pattern )
+regexp* regex_compile( OBJECT* pattern )
{
- regex_entry entry, *e = &entry;
- entry.pattern = pattern;
+ int found;
+ regex_entry * e ;
if ( !regex_hash )
regex_hash = hashinit(sizeof(regex_entry), "regex");
- if ( hashenter( regex_hash, (HASHDATA **)&e ) )
+ e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
+ if ( !found )
+ {
+ e->pattern = object_copy( pattern );
e->regex = regcomp( (char*)pattern );
+ }
return e->regex;
}
-LIST*
-builtin_subst(
- PARSE *parse,
- FRAME *frame )
+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 ( arg1 && list_next(arg1) && list_next(list_next(arg1)) )
+ if ( iter != end && list_next( iter ) != end && list_next( list_next( iter ) ) != end )
{
- const char* source = arg1->string;
- const char* pattern = list_next(arg1)->string;
+ 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) )
{
- LIST* subst = list_next(arg1);
+ LISTITER subst = list_next( iter );
- while ((subst = list_next(subst)) != L0)
+ while ( ( subst = list_next( subst ) ) != end )
{
# define BUFLEN 4096
char buf[BUFLEN + 1];
- const char* in = subst->string;
+ const char* in = object_str( list_item( subst ) );
char* out = buf;
- for ( in = subst->string; *in && out < buf + BUFLEN; ++in )
+ for ( ; *in && out < buf + BUFLEN; ++in )
{
if ( *in == '\\' || *in == '$' )
{
@@ -83,7 +85,7 @@ builtin_subst(
}
*out = 0;
- result = list_new( result, newstr( buf ) );
+ result = list_push_back( result, object_new( buf ) );
#undef BUFLEN
}
}
@@ -92,3 +94,20 @@ builtin_subst(
return result;
}
+
+static void free_regex( void * xregex, void * data )
+{
+ regex_entry * regex = (regex_entry *)xregex;
+ object_free( regex->pattern );
+ BJAM_FREE( regex->regex );
+}
+
+
+void regex_done()
+{
+ if ( regex_hash )
+ {
+ hashenumerate( regex_hash, free_regex, (void *)0 );
+ hashdone( regex_hash );
+ }
+}
diff --git a/tools/build/v2/engine/timestamp.c b/tools/build/v2/engine/timestamp.c
index 8a59c8c0e0..6e4ed7326a 100644
--- a/tools/build/v2/engine/timestamp.c
+++ b/tools/build/v2/engine/timestamp.c
@@ -16,7 +16,7 @@
# include "filesys.h"
# include "pathsys.h"
# include "timestamp.h"
-# include "newstr.h"
+# include "object.h"
# include "strings.h"
/*
@@ -32,12 +32,12 @@
typedef struct _binding BINDING;
struct _binding {
- char *name;
- short flags;
+ OBJECT * name;
+ short flags;
# 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 */
@@ -45,11 +45,11 @@ struct _binding {
# define BIND_MISSING 3 /* file found but can't get timestamp */
# define BIND_FOUND 4 /* file found and time stamped */
- time_t time; /* update time - 0 if not exist */
+ time_t time; /* update time - 0 if not exist */
};
static struct hash * bindhash = 0;
-static void time_enter( void *, char *, int, time_t );
+static void time_enter( void *, OBJECT *, int, time_t );
static char * time_progress[] =
{
@@ -65,49 +65,32 @@ static char * time_progress[] =
* timestamp() - return timestamp on a file, if present.
*/
-void timestamp( char * target, time_t * time )
+void timestamp( OBJECT * target, time_t * time )
{
PROFILE_ENTER( timestamp );
PATHNAME f1;
PATHNAME f2;
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
string buf[ 1 ];
-#ifdef DOWNSHIFT_PATHS
- string path;
- char * p;
-#endif
-#ifdef DOWNSHIFT_PATHS
- string_copy( &path, target );
- p = path.value;
+ target = path_as_key( target );
- do
- {
- *p = tolower( *p );
-#ifdef NT
- /* On NT, we must use backslashes or the file will not be found. */
- if ( *p == '/' )
- *p = PATH_DELIM;
-#endif
- }
- while ( *p++ );
-
- target = path.value;
-#endif /* #ifdef DOWNSHIFT_PATHS */
string_new( buf );
if ( !bindhash )
bindhash = hashinit( sizeof( BINDING ), "bindings" );
/* Quick path - is it there? */
- b->name = target;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( target ); /* never freed */
+ 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;
@@ -115,37 +98,44 @@ void timestamp( char * target, time_t * time )
b->progress = BIND_NOENTRY;
/* Not found - have to scan for it. */
- path_parse( target, &f1 );
+ path_parse( object_str( target ), &f1 );
/* Scan directory if not already done so. */
{
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
+ OBJECT * name;
f2 = f1;
f2.f_grist.len = 0;
path_parent( &f2 );
path_build( &f2, buf, 0 );
- b->name = buf->value;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
+ name = object_new( buf->value );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( buf->value ); /* never freed */
+ 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( buf->value, time_enter, bindhash );
+ file_dirscan( name, time_enter, bindhash );
b->flags |= BIND_SCANNED;
}
+
+ object_free( name );
}
/* Scan archive if not already done so. */
if ( f1.f_member.len )
{
- BINDING binding;
- BINDING * b = &binding;
+ int found;
+ BINDING * b;
+ OBJECT * name;
f2 = f1;
f2.f_grist.len = 0;
@@ -153,18 +143,23 @@ void timestamp( char * target, time_t * time )
string_truncate( buf, 0 );
path_build( &f2, buf, 0 );
- b->name = buf->value;
- b->time = b->flags = 0;
- b->progress = BIND_INIT;
+ name = object_new( buf->value );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( buf->value ); /* never freed */
+ 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 );
}
afterscanning:
@@ -178,43 +173,41 @@ void timestamp( char * target, time_t * time )
*time = b->progress == BIND_FOUND ? b->time : 0;
string_free( buf );
-#ifdef DOWNSHIFT_PATHS
- string_free( &path );
-#endif
+
+ object_free( target );
PROFILE_EXIT( timestamp );
}
-static void time_enter( void * closure, char * target, int found, time_t time )
+static void time_enter( void * closure, OBJECT * target, int found, time_t time )
{
- BINDING binding;
- BINDING * b = &binding;
+ int item_found;
+ BINDING * b;
struct hash * bindhash = (struct hash *)closure;
-#ifdef DOWNSHIFT_PATHS
- char path[ MAXJPATH ];
- char * p = path;
-
- do *p++ = tolower( *target );
- while ( *target++ );
-
- target = path;
-#endif
-
- b->name = target;
- b->flags = 0;
+ target = path_as_key( target );
- if ( hashenter( bindhash, (HASHDATA * *)&b ) )
- b->name = newstr( target ); /* never freed */
+ b = (BINDING *)hash_insert( bindhash, target, &item_found );
+ if ( !item_found )
+ {
+ b->name = object_copy( target );
+ b->flags = 0;
+ }
b->time = time;
b->progress = found ? BIND_FOUND : BIND_SPOTTED;
if ( DEBUG_BINDSCAN )
- printf( "time ( %s ) : %s\n", 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 )
+{
+ object_free( ((BINDING *)xbinding)->name );
+}
/*
* stamps_done() - free timestamp tables.
@@ -222,5 +215,9 @@ static void time_enter( void * closure, char * target, int found, time_t time )
void stamps_done()
{
- hashdone( bindhash );
+ if ( bindhash )
+ {
+ hashenumerate( bindhash, free_timestamps, (void *)0 );
+ hashdone( bindhash );
+ }
}
diff --git a/tools/build/v2/engine/timestamp.h b/tools/build/v2/engine/timestamp.h
index f575276393..26b7e8d1c9 100644
--- a/tools/build/v2/engine/timestamp.h
+++ b/tools/build/v2/engine/timestamp.h
@@ -8,5 +8,13 @@
* timestamp.h - get the timestamp of a file or archive member
*/
-void timestamp( char * target, time_t * time );
+#ifndef TIMESTAMP_H_SW_2011_11_18
+#define TIMESTAMP_H_SW_2011_11_18
+
+#include "object.h"
+#include "time.h"
+
+void timestamp( OBJECT * target, time_t * time );
void stamps_done();
+
+#endif
diff --git a/tools/build/v2/engine/variable.c b/tools/build/v2/engine/variable.c
index 795f345846..21eedf395a 100644
--- a/tools/build/v2/engine/variable.c
+++ b/tools/build/v2/engine/variable.c
@@ -16,12 +16,12 @@
#include "lists.h"
#include "parse.h"
#include "variable.h"
-#include "expand.h"
#include "hash.h"
#include "filesys.h"
-#include "newstr.h"
+#include "object.h"
#include "strings.h"
#include "pathsys.h"
+#include "modules.h"
#include <stdlib.h>
#include <stdio.h>
@@ -49,8 +49,6 @@
* 09/11/00 (seiwald) - defunct var_list() removed
*/
-static struct hash *varhash = 0;
-
/*
* VARIABLE - a user defined multi-value variable
*/
@@ -59,26 +57,12 @@ typedef struct _variable VARIABLE ;
struct _variable
{
- char * symbol;
- LIST * value;
+ OBJECT * symbol;
+ LIST * value;
};
-static VARIABLE * var_enter( char * symbol );
-static void var_dump( char * symbol, LIST * value, char * what );
-
-
-/*
- * var_hash_swap() - swap all variable settings with those passed
- *
- * Used to implement separate settings spaces for modules
- */
-
-void var_hash_swap( struct hash * * new_vars )
-{
- struct hash * old = varhash;
- varhash = *new_vars;
- *new_vars = old;
-}
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol );
+static void var_dump( OBJECT * symbol, LIST * value, char * what );
/*
@@ -94,7 +78,7 @@ void var_hash_swap( struct hash * * new_vars )
* Otherwise, split the value at blanks.
*/
-void var_defines( char * const * e, int preprocess )
+void var_defines( struct module_t * module, char * const * e, int preprocess )
{
string buf[1];
@@ -103,6 +87,7 @@ void var_defines( char * const * e, int preprocess )
for ( ; *e; ++e )
{
char * val;
+ OBJECT * varname;
# ifdef OS_MAC
/* On the mac (MPW), the var=val is actually var\0val */
@@ -133,7 +118,7 @@ void var_defines( char * const * e, int preprocess )
if ( quoted && preprocess )
{
string_append_range( buf, val + 2, val + len );
- l = list_new( l, newstr( buf->value ) );
+ l = list_push_back( l, object_new( buf->value ) );
string_truncate( buf, 0 );
}
else
@@ -156,16 +141,18 @@ void var_defines( char * const * e, int preprocess )
)
{
string_append_range( buf, pp, p );
- l = list_new( l, newstr( buf->value ) );
+ l = list_push_back( l, object_new( buf->value ) );
string_truncate( buf, 0 );
}
- l = list_new( l, newstr( pp ) );
+ l = list_push_back( l, object_new( pp ) );
}
/* Get name. */
string_append_range( buf, *e, val );
- var_set( buf->value, l, VAR_SET );
+ varname = object_new( buf->value );
+ var_set( module, varname, l, VAR_SET );
+ object_free( varname );
string_truncate( buf, 0 );
}
}
@@ -173,304 +160,7 @@ void var_defines( char * const * e, int preprocess )
}
-/*
- * var_string() - expand a string with variables in it
- *
- * Copies in to out; doesn't modify targets & sources.
- */
-
-int var_string( char * in, char * out, int outsize, LOL * lol )
-{
- char * out0 = out;
- char * oute = out + outsize - 1;
-
- while ( *in )
- {
- char * lastword;
- int dollar = 0;
-
- /* Copy white space. */
- while ( isspace( *in ) )
- {
- if ( out >= oute )
- return -1;
- *out++ = *in++;
- }
-
- lastword = out;
-
- /* Copy non-white space, watching for variables. */
- while ( *in && !isspace( *in ) )
- {
- if ( out >= oute )
- return -1;
-
- if ( ( in[ 0 ] == '$' ) && ( in[ 1 ] == '(' ) )
- {
- ++dollar;
- *out++ = *in++;
- }
- #ifdef OPT_AT_FILES
- else if ( ( in[ 0 ] == '@' ) && ( in[ 1 ] == '(' ) )
- {
- int depth = 1;
- char * ine = in + 2;
- char * split = 0;
-
- /* Scan the content of the response file @() section. */
- while ( *ine && ( depth > 0 ) )
- {
- switch ( *ine )
- {
- case '(': ++depth; break;
- case ')': --depth; break;
- case ':':
- if ( ( depth == 1 ) && ( ine[ 1 ] == 'E' ) && ( ine[ 2 ] == '=' ) )
- split = ine;
- break;
- }
- ++ine;
- }
-
- if ( !split )
- {
- /* the @() reference doesn't match the @(foo:E=bar) format.
- hence we leave it alone by copying directly to output. */
- int l = 0;
- if ( out + 2 >= oute ) return -1;
- *( out++ ) = '@';
- *( out++ ) = '(';
- l = var_string( in + 2, out, oute - out, lol );
- if ( l < 0 ) return -1;
- out += l;
- if ( out + 1 >= oute ) return -1;
- *( out++ ) = ')';
- }
- else if ( depth == 0 )
- {
- string file_name_v;
- int file_name_l = 0;
- const char * file_name_s = 0;
-
- /* Expand the temporary file name var inline. */
- #if 0
- string_copy( &file_name_v, "$(" );
- string_append_range( &file_name_v, in + 2, split );
- string_push_back( &file_name_v, ')' );
- #else
- string_new( &file_name_v );
- string_append_range( &file_name_v, in + 2, split );
- #endif
- file_name_l = var_string( file_name_v.value, out, oute - out + 1, lol );
- string_free( &file_name_v );
- if ( file_name_l < 0 ) return -1;
- file_name_s = out;
-
- /* 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;
- out[ 0 ] = '\0';
- file_name_s = path_tmpfile();
- file_name_l = strlen(file_name_s);
- #ifdef OS_NT
- if ( ( out + 7 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
- return -1;
- sprintf( out,"type \"%s\"%s", file_name_s,
- err_redir ? " 1>&2" : "" );
- #else
- if ( ( out + 6 + file_name_l + ( err_redir ? 5 : 0 ) ) >= oute )
- return -1;
- sprintf( out,"cat \"%s\"%s", file_name_s,
- err_redir ? " 1>&2" : "" );
- #endif
- /* We also make sure that the temp files created by this
- * get nuked eventually.
- */
- file_remove_atexit( file_name_s );
- }
-
- /* Expand the file value into the file reference. */
- var_string_to_file( split + 3, ine - split - 4, file_name_s,
- lol );
-
- /* Continue on with the expansion. */
- out += strlen( out );
- }
-
- /* And continue with the parsing just past the @() reference. */
- in = ine;
- }
- #endif
- else
- {
- *out++ = *in++;
- }
- }
-
- /* Add zero to 'out' so that 'lastword' is correctly zero-terminated. */
- if ( out >= oute )
- return -1;
- /* Do not increment, intentionally. */
- *out = '\0';
-
- /* If a variable encountered, expand it and and embed the
- * space-separated members of the list in the output.
- */
- if ( dollar )
- {
- LIST * l = var_expand( L0, lastword, out, lol, 0 );
-
- out = lastword;
-
- while ( l )
- {
- int so = strlen( l->string );
-
- if ( out + so >= oute )
- return -1;
-
- strcpy( out, l->string );
- out += so;
- l = list_next( l );
- if ( l ) *out++ = ' ';
- }
-
- list_free( l );
- }
- }
-
- if ( out >= oute )
- return -1;
-
- *out++ = '\0';
-
- return out - out0;
-}
-
-
-void var_string_to_file( const char * in, int insize, const char * out, LOL * lol )
-{
- char const * ine = in + insize;
- FILE * out_file = 0;
- int out_debug = DEBUG_EXEC ? 1 : 0;
- if ( globs.noexec )
- {
- /* out_debug = 1; */
- }
- else if ( strcmp( out, "STDOUT" ) == 0 )
- {
- out_file = stdout;
- }
- else if ( strcmp( out, "STDERR" ) == 0 )
- {
- out_file = stderr;
- }
- else
- {
- /* Handle "path to file" filenames. */
- string out_name;
- 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 );
- exit( EXITBAD );
- }
- string_free( &out_name );
- }
-
- if ( out_debug ) printf( "\nfile %s\n", out );
-
- while ( *in && ( in < ine ) )
- {
- int dollar = 0;
- const char * output_0 = in;
- const char * output_1 = in;
-
- /* Copy white space. */
- while ( ( output_1 < ine ) && isspace( *output_1 ) )
- ++output_1;
-
- if ( output_0 < output_1 )
- {
- if ( out_file ) fwrite( output_0, output_1 - output_0, 1, out_file );
- if ( out_debug ) fwrite( output_0, output_1 - output_0, 1, stdout );
- }
- output_0 = output_1;
-
- /* Copy non-white space, watching for variables. */
- while ( ( output_1 < ine ) && *output_1 && !isspace( *output_1 ) )
- {
- if ( ( output_1[ 0 ] == '$' ) && ( output_1[ 1 ] == '(' ) )
- ++dollar;
- ++output_1;
- }
-
- /* If a variable encountered, expand it and embed the space-separated
- * members of the list in the output.
- */
- if ( dollar )
- {
- LIST * l = var_expand( L0, (char *)output_0, (char *)output_1, lol, 0 );
-
- while ( l )
- {
- if ( out_file ) fputs( l->string, out_file );
- if ( out_debug ) puts( l->string );
- l = list_next( l );
- if ( l )
- {
- if ( out_file ) fputc( ' ', out_file );
- if ( out_debug ) fputc( ' ', stdout );
- }
- }
-
- list_free( l );
- }
- else if ( output_0 < output_1 )
- {
- if ( out_file )
- {
- const char * output_n = output_0;
- while ( output_n < output_1 )
- {
- output_n += fwrite( output_n, 1, output_1-output_n, out_file );
- }
- }
- if ( out_debug )
- {
- const char * output_n = output_0;
- while ( output_n < output_1 )
- {
- output_n += fwrite( output_n, 1, output_1-output_n, stdout );
- }
- }
- }
-
- in = output_1;
- }
-
- if ( out_file && ( out_file != stdout ) && ( out_file != stderr ) )
- {
- fflush( out_file );
- fclose( out_file );
- }
-
- if ( out_debug ) fputc( '\n', stdout );
-}
-
+static LIST * saved_var = L0;
/*
* var_get() - get value of a user defined symbol.
@@ -478,40 +168,49 @@ void var_string_to_file( const char * in, int insize, const char * out, LOL * lo
* Returns NULL if symbol unset.
*/
-LIST * var_get( char * symbol )
+LIST * var_get( struct module_t * module, OBJECT * symbol )
{
- LIST * result = 0;
+ LIST * result = L0;
#ifdef OPT_AT_FILES
/* Some "fixed" variables... */
- if ( strcmp( "TMPDIR", symbol ) == 0 )
+ if ( object_equal( symbol, constant_TMPDIR ) )
{
- result = list_new( L0, newstr( (char *)path_tmpdir() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_new( path_tmpdir() ) );
}
- else if ( strcmp( "TMPNAME", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_TMPNAME ) )
{
- result = list_new( L0, newstr( (char *)path_tmpnam() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( path_tmpnam() );
}
- else if ( strcmp( "TMPFILE", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_TMPFILE ) )
{
- result = list_new( L0, newstr( (char *)path_tmpfile() ) );
+ list_free( saved_var );
+ result = saved_var = list_new( path_tmpfile() );
}
- else if ( strcmp( "STDOUT", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_STDOUT ) )
{
- result = list_new( L0, newstr( "STDOUT" ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_copy( constant_STDOUT ) );
}
- else if ( strcmp( "STDERR", symbol ) == 0 )
+ else if ( object_equal( symbol, constant_STDERR ) )
{
- result = list_new( L0, newstr( "STDERR" ) );
+ list_free( saved_var );
+ result = saved_var = list_new( object_copy( constant_STDERR ) );
}
else
#endif
{
- VARIABLE var;
- VARIABLE * v = &var;
+ VARIABLE * v;
+ int n;
- v->symbol = symbol;
-
- if ( varhash && hashcheck( varhash, (HASHDATA * *)&v ) )
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ if ( DEBUG_VARGET )
+ var_dump( symbol, module->fixed_variables[ n ], "get" );
+ result = module->fixed_variables[ n ];
+ }
+ else if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
{
if ( DEBUG_VARGET )
var_dump( v->symbol, v->value, "get" );
@@ -522,6 +221,20 @@ LIST * var_get( char * symbol )
}
+LIST * var_get_and_clear_raw( module_t * module, OBJECT * symbol )
+{
+ LIST * result = L0;
+ VARIABLE * v;
+
+ if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
+ {
+ result = v->value;
+ v->value = L0;
+ }
+
+ return result;
+}
+
/*
* var_set() - set a variable in Jam's user defined symbol table.
*
@@ -532,9 +245,9 @@ LIST * var_get( char * symbol )
* Copies symbol. Takes ownership of value.
*/
-void var_set( char * symbol, LIST * value, int flag )
+void var_set( struct module_t * module, OBJECT * symbol, LIST * value, int flag )
{
- VARIABLE * v = var_enter( symbol );
+ LIST * * v = var_enter( module, symbol );
if ( DEBUG_VARSET )
var_dump( symbol, value, "set" );
@@ -543,19 +256,19 @@ void var_set( char * symbol, LIST * value, int flag )
{
case VAR_SET:
/* Replace value */
- list_free( v->value );
- v->value = value;
+ list_free( *v );
+ *v = value;
break;
case VAR_APPEND:
/* Append value */
- v->value = list_append( v->value, value );
+ *v = list_append( *v, value );
break;
case VAR_DEFAULT:
/* Set only if unset */
- if ( !v->value )
- v->value = value;
+ if ( list_empty( *v ) )
+ *v = value;
else
list_free( value );
break;
@@ -567,13 +280,13 @@ void var_set( char * symbol, LIST * value, int flag )
* var_swap() - swap a variable's value with the given one.
*/
-LIST * var_swap( char * symbol, LIST * value )
+LIST * var_swap( struct module_t * module, OBJECT * symbol, LIST * value )
{
- VARIABLE * v = var_enter( symbol );
- LIST * oldvalue = v->value;
+ LIST * * v = var_enter( module, symbol );
+ LIST * oldvalue = *v;
if ( DEBUG_VARSET )
var_dump( symbol, value, "set" );
- v->value = value;
+ *v = value;
return oldvalue;
}
@@ -582,21 +295,28 @@ LIST * var_swap( char * symbol, LIST * value )
* var_enter() - make new var symbol table entry, returning var ptr.
*/
-static VARIABLE * var_enter( char * symbol )
+static LIST * * var_enter( struct module_t * module, OBJECT * symbol )
{
- VARIABLE var;
- VARIABLE * v = &var;
+ int found;
+ VARIABLE * v;
+ int n;
- if ( !varhash )
- varhash = hashinit( sizeof( VARIABLE ), "variables" );
+ if ( ( n = module_get_fixed_var( module, symbol ) ) != -1 )
+ {
+ return &module->fixed_variables[ n ];
+ }
- v->symbol = symbol;
- v->value = 0;
+ if ( !module->variables )
+ module->variables = hashinit( sizeof( VARIABLE ), "variables" );
- if ( hashenter( varhash, (HASHDATA * *)&v ) )
- v->symbol = newstr( symbol ); /* never freed */
+ v = (VARIABLE *)hash_insert( module->variables, symbol, &found );
+ if ( !found )
+ {
+ v->symbol = object_copy( symbol );
+ v->value = L0;
+ }
- return v;
+ return &v->value;
}
@@ -604,9 +324,9 @@ static VARIABLE * var_enter( char * symbol )
* var_dump() - dump a variable to stdout.
*/
-static void var_dump( char * symbol, LIST * value, char * what )
+static void var_dump( OBJECT * symbol, LIST * value, char * what )
{
- printf( "%s %s = ", what, symbol );
+ printf( "%s %s = ", what, object_str( symbol ) );
list_print( value );
printf( "\n" );
}
@@ -619,13 +339,15 @@ static void var_dump( char * symbol, LIST * value, char * what )
static void delete_var_( void * xvar, void * data )
{
VARIABLE * v = (VARIABLE *)xvar;
- freestr( v->symbol );
+ object_free( v->symbol );
list_free( v-> value );
}
-void var_done()
+void var_done( struct module_t * module )
{
- hashenumerate( varhash, delete_var_, (void *)0 );
- hashdone( varhash );
+ list_free( saved_var );
+ saved_var = L0;
+ hashenumerate( module->variables, delete_var_, (void *)0 );
+ hash_free( module->variables );
}
diff --git a/tools/build/v2/engine/variable.h b/tools/build/v2/engine/variable.h
index 5c49e3ca55..aa27d56d6b 100644
--- a/tools/build/v2/engine/variable.h
+++ b/tools/build/v2/engine/variable.h
@@ -8,22 +8,16 @@
* variable.h - handle jam multi-element variables
*/
-struct hash;
+#ifndef VARIABLE_SW20111119_H
+#define VARIABLE_SW20111119_H
-void var_defines( char* const *e, int preprocess );
-int var_string( char *in, char *out, int outsize, LOL *lol );
-LIST * var_get( char *symbol );
-void var_set( char *symbol, LIST *value, int flag );
-LIST * var_swap( char *symbol, LIST *value );
-void var_done();
-void var_hash_swap( struct hash** );
+struct module_t;
-/** Expands the "in" expression directly into the "out" file.
- The file can be one of: a path, STDOUT, or STDERR to send
- the output to a file overwriting previous content, to
- the console, or to the error output respectively.
-*/
-void var_string_to_file( const char * in, int insize, const char * out, LOL * lol );
+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 );
/*
* Defines for var_set().
@@ -33,3 +27,4 @@ void var_string_to_file( const char * in, int insize, const char * out, LOL * lo
# define VAR_APPEND 1 /* append to previous value */
# define VAR_DEFAULT 2 /* set only if no previous value */
+#endif
diff --git a/tools/build/v2/engine/w32_getreg.c b/tools/build/v2/engine/w32_getreg.c
index 5a06f43e92..dd2d0fc70c 100644
--- a/tools/build/v2/engine/w32_getreg.c
+++ b/tools/build/v2/engine/w32_getreg.c
@@ -9,7 +9,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# if defined( OS_NT ) || defined( OS_CYGWIN )
# include "lists.h"
-# include "newstr.h"
+# include "object.h"
# include "parse.h"
# include "frames.h"
# include "strings.h"
@@ -57,12 +57,9 @@ static HKEY get_key(char const** path)
return p->value;
}
-LIST*
-builtin_system_registry(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry( FRAME * frame, int flags )
{
- char const* path = lol_get(frame->args, 0)->string;
+ char const* path = object_str( list_front( lol_get(frame->args, 0) ) );
LIST* result = L0;
HKEY key = get_key(&path);
@@ -74,10 +71,10 @@ builtin_system_registry(
DWORD type;
BYTE data[MAX_REGISTRY_DATA_LENGTH];
DWORD len = sizeof(data);
- LIST const* const field = lol_get(frame->args, 1);
+ LIST * const field = lol_get(frame->args, 1);
if ( ERROR_SUCCESS ==
- RegQueryValueEx(key, field ? field->string : 0, 0, &type, data, &len) )
+ RegQueryValueEx(key, field ? object_str( list_front( field ) ) : 0, 0, &type, data, &len) )
{
switch (type)
{
@@ -97,7 +94,7 @@ builtin_system_registry(
expanded->size = len - 1;
- result = list_new( result, newstr(expanded->value) );
+ result = list_push_back( result, object_new(expanded->value) );
string_free( expanded );
}
break;
@@ -107,7 +104,7 @@ builtin_system_registry(
char* s;
for (s = (char*)data; *s; s += strlen(s) + 1)
- result = list_new( result, newstr(s) );
+ result = list_push_back( result, object_new(s) );
}
break;
@@ -116,12 +113,12 @@ builtin_system_registry(
{
char buf[100];
sprintf( buf, "%u", *(PDWORD)data );
- result = list_new( result, newstr(buf) );
+ result = list_push_back( result, object_new(buf) );
}
break;
case REG_SZ:
- result = list_new( result, newstr((char*)data) );
+ result = list_push_back( result, object_new( (const char *)data ) );
break;
}
}
@@ -151,7 +148,7 @@ static LIST* get_subkey_names(HKEY key, char const* path)
)
{
name[name_size] = 0;
- result = list_append(result, list_new(0, newstr(name)));
+ result = list_append(result, list_new(object_new(name)));
}
RegCloseKey(key);
@@ -178,7 +175,7 @@ static LIST* get_value_names(HKEY key, char const* path)
)
{
name[name_size] = 0;
- result = list_append(result, list_new(0, newstr(name)));
+ result = list_append(result, list_new(object_new(name)));
}
RegCloseKey(key);
@@ -187,13 +184,10 @@ static LIST* get_value_names(HKEY key, char const* path)
return result;
}
-LIST*
-builtin_system_registry_names(
- PARSE *parse,
- FRAME *frame )
+LIST * builtin_system_registry_names( FRAME * frame, int flags )
{
- char const* path = lol_get(frame->args, 0)->string;
- char const* result_type = lol_get(frame->args, 1)->string;
+ char const* path = object_str( list_front( lol_get(frame->args, 0) ) );
+ char const* result_type = object_str( list_front( lol_get(frame->args, 1) ) );
HKEY key = get_key(&path);
diff --git a/tools/build/v2/test/BoostBuild.py b/tools/build/v2/test/BoostBuild.py
index 409a51b6e9..9ad9202877 100644
--- a/tools/build/v2/test/BoostBuild.py
+++ b/tools/build/v2/test/BoostBuild.py
@@ -76,19 +76,30 @@ def get_toolset():
# Detect the host OS.
windows = False
-if os.environ.get('OS', '').lower().startswith('windows') or \
- os.__dict__.has_key('uname') and \
- os.uname()[0].lower().startswith('cygwin'):
+cygwin = False
+if os.environ.get('OS', '').lower().startswith('windows'):
windows = True
+if os.__dict__.has_key('uname') and \
+ os.uname()[0].lower().startswith('cygwin'):
+ windows = True
+ cygwin = True
suffixes = {}
+# 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
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'
if windows:
@@ -96,9 +107,19 @@ def prepare_suffix_map(toolset):
if toolset in ["gcc"]:
suffixes['.lib'] = '.a' # static libs have '.a' suffix with mingw...
suffixes['.obj'] = '.o'
- suffixes['.implib'] = '.lib'
+ if cygwin:
+ suffixes['.implib'] = '.lib.a'
+ else:
+ suffixes['.implib'] = '.lib'
if os.__dict__.has_key('uname') and (os.uname()[0] == 'Darwin'):
suffixes['.dll'] = '.dylib'
+
+ lib_prefix = "lib"
+ dll_prefix = "lib"
+ if cygwin:
+ dll_prefix = "cyg"
+ elif windows and not toolset in ["gcc"]:
+ dll_prefix = None
def re_remove(sequence, regex):
@@ -118,13 +139,6 @@ def glob_remove(sequence, pattern):
sequence.remove(r)
-# Configuration stating whether Boost Build is expected to automatically prepend
-# prefixes to built library targets.
-lib_prefix = True
-dll_prefix = True
-if windows:
- dll_prefix = False
-
#
# FIXME: this is copy-pasted from TestSCons.py
@@ -192,7 +206,7 @@ class Tester(TestCmd.TestCmd):
def __init__(self, arguments="", 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="", **keywords):
+ ignore_toolset_requirements=True, workdir="", pass_d0=True, **keywords):
self.original_workdir = os.getcwd()
if workdir != '' and not os.path.isabs(workdir):
@@ -259,6 +273,8 @@ class Tester(TestCmd.TestCmd):
sys.exit(1)
verbosity = ['-d0', '--quiet']
+ if not pass_d0:
+ verbosity = []
if '--verbose' in sys.argv:
keywords['verbose'] = True
verbosity = ['-d+2']
@@ -365,9 +381,16 @@ class Tester(TestCmd.TestCmd):
os.utime(self.native_file_name(name), None)
def rm(self, names):
- self.wait_for_time_change_since_last_build()
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()
# Avoid attempts to remove the current directory.
os.chdir(self.original_workdir)
@@ -495,6 +518,10 @@ class Tester(TestCmd.TestCmd):
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)
@@ -795,6 +822,7 @@ class Tester(TestCmd.TestCmd):
def adjust_lib_name(self, name):
global lib_prefix
+ global dll_prefix
result = name
pos = string.rfind(name, ".")
@@ -803,12 +831,12 @@ class Tester(TestCmd.TestCmd):
if suffix == ".lib":
(head, tail) = os.path.split(name)
if lib_prefix:
- tail = "lib" + tail
+ tail = lib_prefix + tail
result = os.path.join(head, tail)
elif suffix == ".dll":
(head, tail) = os.path.split(name)
if dll_prefix:
- tail = "lib" + tail
+ 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 \.
diff --git a/tools/build/v2/test/Jamrules b/tools/build/v2/test/Jamrules
deleted file mode 100644
index ff29a26bba..0000000000
--- a/tools/build/v2/test/Jamrules
+++ /dev/null
@@ -1,4 +0,0 @@
-# This simple Jamrules file is used for the Boost.Build test project.
-
-# The testing framework itself gets no boost-Jambase
-BOOST_JAMBASE = empty.jam ;
diff --git a/tools/build/v2/test/absolute_sources.py b/tools/build/v2/test/absolute_sources.py
index 58e2cf4516..4053b35ca1 100644
--- a/tools/build/v2/test/absolute_sources.py
+++ b/tools/build/v2/test/absolute_sources.py
@@ -26,6 +26,7 @@ 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
diff --git a/tools/build/v2/test/assert-equal.jam b/tools/build/v2/test/assert-equal.jam
deleted file mode 100644
index 6ed501e74b..0000000000
--- a/tools/build/v2/test/assert-equal.jam
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2001 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)
-
-# Evaluates [ rulename arg1... : arg2... : ... : argN... ] and compares the
-# result to expected-results. If there is a mismatch, prints an error message
-# and exits.
-rule assert-equal ( expected-results *
- : rulename a1 * : a2 * : a3 * : a4 * : a5 * : a6 * : a7 * : a8 * : a9 * )
-{
-
- local results = [ $(rulename) $(a1) : $(a2) : $(a3)
- : $(a4) : $(a5) : $(a6) : $(a7) : $(a8) ] ;
-
- if $(results) != $(expected-results)
- {
- EXIT ******ASSERTION FAILURE******* "
- [ $(rulename) " $(a1)
- ": "$(a2[1]) $(a2[2-])
- ": "$(a3[1]) $(a3[2-])
- ": "$(a4[1]) $(a4[2-])
- ": "$(a5[1]) $(a5[2-])
- ": "$(a6[1]) $(a6[2-])
- ": "$(a7[1]) $(a7[2-])
- ": "$(a8[1]) $(a8[2-]) "]
-expected:
- (" $(expected-results) ")
-result was:
- (" $(results) ")"
- ;
-
- }
-}
diff --git a/tools/build/v2/test/builtin_echo.py b/tools/build/v2/test/builtin_echo.py
new file mode 100755
index 0000000000..4d57e96bfc
--- /dev/null
+++ b/tools/build/v2/test/builtin_echo.py
@@ -0,0 +1,30 @@
+#!/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)
+
+# This tests the ECHO rule.
+
+import BoostBuild
+
+def test_echo(name):
+ t = BoostBuild.Tester(pass_toolset=0)
+
+ t.write("file.jam", """
+ %s ;
+ UPDATE ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="\n")
+
+ t.write("file.jam", """
+ %s a message ;
+ UPDATE ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="a message\n")
+
+ t.cleanup()
+
+test_echo("ECHO")
+test_echo("Echo")
+test_echo("echo")
diff --git a/tools/build/v2/test/builtin_exit.py b/tools/build/v2/test/builtin_exit.py
new file mode 100755
index 0000000000..2e4fd1215c
--- /dev/null
+++ b/tools/build/v2/test/builtin_exit.py
@@ -0,0 +1,54 @@
+#!/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)
+
+# This tests the EXIT rule.
+
+import BoostBuild
+
+def test_exit(name):
+ t = BoostBuild.Tester(pass_toolset=0)
+
+ t.write("file.jam", """
+ %s ;
+ """ % name)
+ t.run_build_system("-ffile.jam", status=1, stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s : 0 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s : 1 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", status=1, stdout="\n")
+ t.rm(".")
+
+ t.write("file.jam", """
+ %s : 2 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", 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.rm(".")
+
+ t.write("file.jam", """
+ %s a message : 0 ;
+ """ % name)
+ t.run_build_system("-ffile.jam", stdout="a message\n")
+ t.rm(".")
+
+ t.cleanup()
+
+test_exit("EXIT")
+test_exit("Exit")
+test_exit("exit")
diff --git a/tools/build/v2/test/check-arguments.jam b/tools/build/v2/test/check-arguments.jam
deleted file mode 100644
index 20e025074d..0000000000
--- a/tools/build/v2/test/check-arguments.jam
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2001 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)
-
-#
-# Jam code for testing the named-argument patch.
-#
-
-include recursive.jam ;
-
-# Prefixes for all of the jam code we're going to test
-local ECHO_ARGS = "include echo_args.jam ; echo_args "
- ;
-
-local ECHO_VARARGS = "include echo_args.jam ; echo_varargs "
- ;
-
-# Check that it will find missing arguments
-Jam-fail $(ECHO_ARGS)";"
- : "missing argument a"
- ;
-
-# Check that it will find if too many arguments are passed
-Jam-fail $(ECHO_ARGS)"1 2 : 3 : 4 : 5 ;"
- : "extra argument 5"
- ;
-
-# Check that it will find when an argument has too many elements
-Jam-fail $(ECHO_ARGS)"a b c1 c2 : d ;"
- : "extra argument c2"
- ;
-
-# Check modifier '?'
-Jam $(ECHO_ARGS)"1 2 3 : 4 ;"
- : "a= 1 b= 2 c= 3 : d= 4 : e=" ;
-Jam $(ECHO_ARGS)"1 2 : 3 ;"
- : "a= 1 b= 2 c= : d= 3 : e=" ;
-Jam $(ECHO_ARGS)"1 : 2 ;"
- : "a= 1 b= c= : d= 2 : e=" ;
-
-# Check modifier '+'
-Jam-fail $(ECHO_ARGS)"1 ;"
- : "missing argument d" ;
-Jam $(ECHO_ARGS)"1 : 2 3 ;"
- : "a= 1 b= c= : d= 2 3 : e=" ;
-Jam $(ECHO_ARGS)"1 : 2 3 4 ;"
- : "a= 1 b= c= : d= 2 3 4 : e=" ;
-
-# Check modifier '*'
-Jam $(ECHO_ARGS)"1 : 2 : 3 ;"
- : "a= 1 b= c= : d= 2 : e= 3" ;
-Jam $(ECHO_ARGS)"1 : 2 : 3 4 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4" ;
-Jam $(ECHO_ARGS)"1 : 2 : 3 4 5 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5" ;
-
-#
-# Check varargs
-#
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 7 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 7 : 8 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8" ;
-Jam $(ECHO_VARARGS)"1 : 2 : 3 4 5 : 6 7 : 8 : 9 ;"
- : "a= 1 b= c= : d= 2 : e= 3 4 5 : rest= 6 7 : 8 : 9" ;
-
-
diff --git a/tools/build/v2/test/check-jam-patches.jam b/tools/build/v2/test/check-jam-patches.jam
deleted file mode 100644
index 7e00bec20c..0000000000
--- a/tools/build/v2/test/check-jam-patches.jam
+++ /dev/null
@@ -1,293 +0,0 @@
-# Copyright 2001, 2002 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)
-
-# Get the recursive Jam invocation code
-include recursive.jam ;
-include assert-equal.jam ;
-
-Jam "include check-bindrule.jam ;"
- : "found: file-to-bind at subdir1$(SLASH)file-to-bind"
- ;
-
-include check-arguments.jam ;
-
-if $(NT)
-{
- # if this one fails, you don't have the line length patch
- Jam "include test_nt_line_length.jam ;" ;
-}
-
-# a little utility for assertions
-rule identity ( list * )
-{
- return $(list) ;
-}
-
-#
-# test rule indirection
-#
-rule select ( n list * )
-{
- return $(list[$(n)]) ;
-}
-
-rule indirect1 ( rule + : args * )
-{
- return [ $(rule) $(args) ] ;
-}
-
-assert-equal a : indirect1 select 1 : a b c d e ;
-assert-equal b : indirect1 select 2 : a b c d e ;
-
-x = reset ;
-rule reset-x ( new-value )
-{
- x = $(new-value) ;
-}
-$(x)-x bar ; # invokes reset-x...
-assert-equal bar : identity $(x) ; # which changes x
-
-# Check that unmatched subst returns an empty list
-assert-equal # nothing
- : SUBST "abc" "d+" x ;
-
-# Check that a matched subst works
-assert-equal x
- : SUBST "ddd" "d+" x ;
-
-# Check that we can get multiple substitutions from a single invocation
-assert-equal x y x-y
- : SUBST "x/y/z" "([^/]*)/([^/]*).*" "\\1" $2 "\\1-\\2" ;
-
-#
-# test local foreach modification
-#
-{
- local x = 0 ;
- local entered = ;
- for local x in a b c # x declared local to for loop.
- {
- entered = 1 ;
- if ! ( $(x) in a b c )
- {
- EXIT "local foreach: expected one of a, b, c; got" $(x) ;
- }
- }
-
- if $(x) != 0 # if x was modified, it failed to be a local variable
- {
- EXIT "local foreach failed" ;
- }
-}
-
-#
-# test while loops
-#
-{
- local x = a b c ;
- local y = $(x) ;
- local z = ;
-
- while $(y)
- {
- z += $(y[1]) ;
- y = $(y[2-]) ;
- }
-
- if $(z) != $(x)
- {
- EXIT "while loops failed" ;
- }
-}
-
-#
-# test negative list indices and slices
-#
-{
- local x = a b c d e ;
-
- rule assert-index ( index : list * )
- {
- if $(x[$(index)]) != $(list)
- {
- ECHO with x= $(x) ;
- ECHO x[$(index)] == $(x[$(index)]) ;
- EXIT expected $(list) ;
- }
- }
-
- assert-index 1 : a ;
- assert-index 3 : c ;
- assert-index 1-2 : a b ;
- assert-index -1 : e ;
- assert-index -2 : d ;
- assert-index 2--2 : b c d ;
- assert-index -3--2 : c d ;
- assert-index 1--2 : a b c d ;
- assert-index 1--2 : a b c d ;
- assert-index 1--10 : ;
- x = a ;
- assert-index 1--2 : ;
- assert-index 1--2 : ;
-}
-
-#
-# test module primitives
-#
-{
- local x = a b c d e f g h i j ;
- local y = $(x[3-]) ;
-
- rule shift1 ( dummy ) { }
-
- rule my_module.not_really ( ) { return something ; }
-
- # import the identity rule into my_module as "id"
- IMPORT : identity : my_module : id ;
- module my_module
- {
- # assert-equal operates in its own module, so call id in here and use
- # identity later.
- local f = [ id x y z ] ;
- assert-equal x y z : identity $(f) ;
-
- w = ;
- y = ;
- x2 = 1 2 3 ;
- x3 = $(x2) ;
- z = $(x2) ;
-
- x3 = ; # should reset x3
-
- # drops one element from the head of x
- # moves the first element of z from the head of z to the head of y
- rule shift1 ( )
- {
- x = $(x[2-]) ;
- y = $(z[1]) $(y) ;
- z = $(z[2-]) ;
- }
-
- rule shift2 ( )
- {
- shift1 ;
- }
-
- shift1 ;
- shift2 ;
-
- rule get ( symbol )
- {
- return $($(symbol)) ;
- }
- local rule not_really ( ) { return nothing ; }
- }
-
- local expected = shift1 shift2 get ;
- if ! ( $(expected) in [ RULENAMES my_module ] )
- || ! ( [ RULENAMES my_module ] in $(expected) )
- {
- EXIT "[ RULENAMES my_module ] =" [ RULENAMES my_module ] "!=" shift1 shift2 get ;
- }
-
-
- # show that not_really was actually a local definition
- assert-equal something : my_module.not_really ;
-
- if not_really in [ RULENAMES my_module ]
- {
- EXIT unexpectedly found local rule "not_really" in "my_module" ;
- }
- EXPORT my_module : not_really ;
-
- if ! ( not_really in [ RULENAMES my_module ] )
- {
- EXIT unexpectedly failed to find exported rule "not_really" in "my_module" ;
- }
-
- # show that my_module doesn't have access to our variables
- my_module.shift1 ;
- assert-equal $(x[3-]) : identity $(y) ;
-
- # check module locals
- assert-equal : my_module.get w ;
- assert-equal 3 2 1 : my_module.get y ;
- assert-equal 1 2 3 : my_module.get x2 ;
- assert-equal : my_module.get x3 ;
- assert-equal : my_module.get z ;
-
- my_module.shift2 ;
- x = $(x[3-]) ;
- assert-equal $(x) : identity $(y) ;
-
- # Prove that the module's rule is not exposed to the world at large without
- # qualification
- shift1 nothing ;
- assert-equal $(x) : identity $(y) ;
-
- # import my_module.shift1 into the global module as "shifty", and
- # my_module.shift2 into the global module as "shift2".
- IMPORT my_module : shift1 shift2 : : shifty shift2 ;
-
- shifty ;
- assert-equal $(x) : identity $(y) ;
-
- shift2 ;
- assert-equal $(x) : identity $(y) ;
-
- # Now do the same with localization
- IMPORT my_module : shift1 : : shifty : LOCALIZE ;
-
- shifty ;
- y = $(y[3-]) ;
- assert-equal $(x) : identity $(y) ;
-
- # import everything from my_module into the global module using
- # the same names.
- IMPORT my_module : [ RULENAMES my_module ] : : [ RULENAMES my_module ] : LOCALIZE ;
-
- shift1 ;
- y = $(y[2-]) ;
- assert-equal $(x) : identity $(y) ;
-
- shift2 ;
- y = $(y[2-]) ;
- assert-equal $(x) : identity $(y) ;
-}
-
-#
-# test CALLER_MODULE and backtrace
-#
-{
- rule backtrace ( )
- {
- local bt = [ BACKTRACE ] ;
- bt = $(bt[5-]) ;
- while $(bt)
- {
- ECHO $(bt[1]):$(bt[2]): "in" $(bt[4]) ;
- bt = $(bt[5-]) ;
- }
- }
- module module1
- {
- rule f ( )
- {
- local m = [ CALLER_MODULE ] ;
- assert-equal : identity $(m) ;
- module2.f ;
- }
-
- }
- module module2
- {
- rule f ( )
- {
- local m = [ CALLER_MODULE ] ;
- assert-equal module1 : identity $(m) ;
- backtrace ;
- }
- }
- module1.f ;
-}
diff --git a/tools/build/v2/test/check-test-tools.jam b/tools/build/v2/test/check-test-tools.jam
deleted file mode 100644
index adf78cc3b4..0000000000
--- a/tools/build/v2/test/check-test-tools.jam
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2001 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)
-
-include recursive.jam ;
-include assert-equal.jam ;
-
-#####################################
-# Test the testing tools right here #
-#####################################
-
-# This command always exits with a failure.
-Jam-fail "EXIT error ;" ;
-
-# This should fail to fail
-Jam-fail
- "include recursive.jam ; Jam-fail \"# this innocuous Jamfile should fail to fail\" ;"
- ;
-
-# the ECHO rule always has an empty result.
-Jam-fail "include assert-equal.jam ; assert-equal fubar : ECHO checking that assertions fail ;"
- : "ASSERTION FAILURE"
- ;
-
-local NOTHING = ;
-assert-equal $(NOTHING) : ECHO checking that assertions succeed ;
diff --git a/tools/build/v2/test/conditionals_multiple.py b/tools/build/v2/test/conditionals_multiple.py
index 20b6b47f7b..d58d86c27e 100755
--- a/tools/build/v2/test/conditionals_multiple.py
+++ b/tools/build/v2/test/conditionals_multiple.py
@@ -21,7 +21,7 @@ def test_multiple_conditions():
"""Basic tests for properties conditioned on multiple other properties.
"""
- t = BoostBuild.Tester("--ignore-regular-config toolset=testToolset",
+ t = BoostBuild.Tester("--user-config= --ignore-site-config toolset=testToolset",
pass_toolset=False, use_test_config=False)
t.write("testToolset.jam", """
@@ -30,6 +30,13 @@ feature.extend toolset : testToolset ;
rule init ( ) { }
""")
+ t.write("testToolset.py", """
+from b2.build import feature
+feature.extend('toolset', ["testToolset"])
+def init ( ):
+ pass
+""")
+
t.write("jamroot.jam", """
import feature ;
import notfile ;
@@ -126,7 +133,7 @@ def test_multiple_conditions_with_toolset_version():
toolset = "testToolset" ;
- t = BoostBuild.Tester("--ignore-regular-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", """
import feature ;
@@ -135,6 +142,14 @@ feature.subfeature toolset %(toolset)s : version : 0 1 ;
rule init ( version ? ) { }
""" % {"toolset": toolset})
+ t.write( "testToolset.py", """
+from b2.build import feature
+feature.extend('toolset', ["testToolset"])
+feature.subfeature('toolset',"testToolset","version",['0','1'])
+def init ( version ):
+ pass
+ """)
+
t.write("jamroot.jam", """
import feature ;
import notfile ;
diff --git a/tools/build/v2/test/configuration.py b/tools/build/v2/test/configuration.py
index 46adfd3c9b..1125db36bd 100755
--- a/tools/build/v2/test/configuration.py
+++ b/tools/build/v2/test/configuration.py
@@ -47,6 +47,14 @@ import feature ;
feature.extend toolset : %s ;
rule init ( ) { }
""" % toolsetName )
+
+ # Python version of 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()
diff --git a/tools/build/v2/test/core-language/test.jam b/tools/build/v2/test/core-language/test.jam
new file mode 100644
index 0000000000..24dcc2924d
--- /dev/null
+++ b/tools/build/v2/test/core-language/test.jam
@@ -0,0 +1,1353 @@
+# 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)
+
+# Tools
+
+passed = 0 ;
+failed = 0 ;
+
+rule show-result ( id : test-result )
+{
+ if ! ( --quiet in $(ARGV) )
+ {
+ ECHO $(test-result): $(id) ;
+ }
+ $(test-result) = [ CALC $($(test-result)) + 1 ] ;
+}
+
+rule check-equal ( id : values * : expected * )
+{
+ local test-result ;
+ if x$(values) = x$(expected)
+ {
+ test-result = passed ;
+ }
+ else
+ {
+ ECHO error: "[" $(values) "] != [" $(expected) "]" ;
+ test-result = failed ;
+ }
+ show-result $(id) : $(test-result) ;
+}
+
+rule mark-order ( id : result * )
+{
+ order += $(id) ;
+ return $(result) ;
+}
+
+rule check-order ( id : expected * )
+{
+ check-equal $(id) : $(order) : $(expected) ;
+ order = ;
+}
+
+# Check variable expansion
+
+{
+
+local v1 = 1 2 3 ;
+local v2 = 4 5 6 ;
+local v3 = 0 1 2 3 4 5 6 7 8 9 10 ;
+local g = g1 g2 ;
+local v4 = String/With/Mixed/Case ;
+local v5 = path\\with\\backslashes ;
+local v6 = <grist>generic/path.txt(member.txt) ;
+local v7 = <Grist1>Dir1/File1.cpp(M1.c) <Grist2>Dir2/File2.hpp(M2.c) ;
+local v8 = <Grist3>Dir3/File3.c(M3.c) <Grist4>Dir4/File4.h(M4.c) ;
+local select1 = GU BL DBST ;
+local case1 = L U ;
+local vars = 7 8 ;
+local sub = 2 1 ;
+local p0 = name ;
+local p1 = dir/name ;
+local p2 = dir/sub/name ;
+local j1 = , - ;
+
+check-equal var-product : $(v1)$(v2) : 14 15 16 24 25 26 34 35 36 ;
+
+check-equal var-set-grist : $(v1:G=grist) : <grist>1 <grist>2 <grist>3 ;
+check-equal var-set-grist-multi : $(v1:G=$(g)) : <g1>1 <g1>2 <g1>3 <g2>1 <g2>2 <g2>3 ;
+
+check-equal var-lower : $(v4:L) : string/with/mixed/case ;
+check-equal var-upper : $(v4:U) : STRING/WITH/MIXED/CASE ;
+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-base : $(v6:B) : path ;
+check-equal var-suffix : $(v6:S) : .txt ;
+check-equal var-dir : $(v6:D) : generic ;
+check-equal var-member : $(v6:M) : (member.txt) ;
+check-equal var-multi : $(v6:$(select1)) : <GRIST> path generic/path.txt ;
+
+check-equal var-join-0 : $(:J=,) : ;
+check-equal var-join-1 : $(p0:J=,) : name ;
+check-equal var-join-3 : $(v1:J=,) : 1,2,3 ;
+check-equal var-set-grist-join : $(v1:G=grist:J=,) : <grist>1,<grist>2,<grist>3 ;
+# behavior change. In the past, a J= modifier would
+# cause only the last element of the other modifiers
+# to take effect.
+check-equal var-set-grist-multi-join : $(v1:G=$(g):J=,) : <g1>1,<g1>2,<g1>3 <g2>1,<g2>2,<g2>3 ;
+check-equal var-set-grist-multi-join-multi : $(v1:G=$(g):J=$(j1)) : <g1>1,<g1>2,<g1>3 <g1>1-<g1>2-<g1>3 <g2>1,<g2>2,<g2>3 <g2>1-<g2>2-<g2>3 ;
+
+check-equal var-D=-0 : name : $(p0:D=) ;
+check-equal var-D=-1 : name : $(p1:D=) ;
+check-equal var-D=-2 : name : $(p2:D=) ;
+check-equal var-D-0 : "" : $(p0:D) ;
+check-equal var-D-1 : dir : $(p1:D) ;
+check-equal var-D-2 : dir/sub : $(p2:D) ;
+check-equal var-S-1 : "" : $(p0:S) ;
+check-equal var-no-at-file-0 : ($(p0)) : [ MATCH ^@(.*) : "@($(p0))" ] ;
+check-equal var-no-at-file-1 : ($(p0)) : [ MATCH @(.*) : "--@($(p0))" ] ;
+
+if $(OS) = CYGWIN
+{
+ local cyg-root = $(:WE=/) ;
+ local cyg1 = /cygdrive/c/path1.txt ;
+ check-equal cygwin-to-cygdrive : $(cyg1:W) : C:\\path1.txt ;
+ local cyg2 = /bin/bash ;
+ check-equal cygwin-to-windows : $(cyg2:W) : $(cyg-root)\\bin\\bash ;
+ check-equal cygwin-combine-WT : $(cyg2:WT) : $(cyg-root)\\bin\\bash ;
+
+ local cyg3 = /home/boost/devel/trunk/bin.v2/ ; # exactly 31 characters
+ local win3 = $(cyg-root)\\home\\boost\\devel\\trunk\\bin.v2\\ ;
+ # This is is the easiest way to demonstrate a bug
+ # that used to cause undefined behavior. Longer paths
+ # resulted in a use-after-free error, which happened
+ # to work most of the time.
+ check-equal cygwin-long-WU : $(cyg3:WU) : $(win3:U) ;
+
+ 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.
+ check-equal cygwin-WL : $(cyg2:WL) : $(cyg-root:L)\\bin\\bash ;
+}
+
+# behavior change
+check-equal var-test1 : $(v7[2]:G:L) : <grist2> ;
+
+check-equal var-multi-product-smm : $(v$(vars)[$(sub)]:G=$(g):$(case1)) :
+ <g1>dir2/file2.hpp(m2.c) <G1>DIR2/FILE2.HPP(M2.C)
+ <g2>dir2/file2.hpp(m2.c) <G2>DIR2/FILE2.HPP(M2.C)
+ <g1>dir1/file1.cpp(m1.c) <G1>DIR1/FILE1.CPP(M1.C)
+ <g2>dir1/file1.cpp(m1.c) <G2>DIR1/FILE1.CPP(M1.C)
+ <g1>dir4/file4.h(m4.c) <G1>DIR4/FILE4.H(M4.C)
+ <g2>dir4/file4.h(m4.c) <G2>DIR4/FILE4.H(M4.C)
+ <g1>dir3/file3.c(m3.c) <G1>DIR3/FILE3.C(M3.C)
+ <g2>dir3/file3.c(m3.c) <G2>DIR3/FILE3.C(M3.C)
+;
+check-equal var-nopathmods : $(:E=//) : // ;
+
+# showcases all the idiosyncracies of indexing
+# key: h = high, l = low, p = positive, m = minus, e = end.
+
+check-equal var-subscript-one-p : $(v3[3]) : 2 ;
+check-equal var-subscript-one-m : $(v3[-3]) : 8 ;
+check-equal var-subscript-one-0 : $(v3[0]) : 0 ;
+check-equal var-subscript-one-h : $(v3[20]) : ;
+check-equal var-subscript-one-l : $(v3[-20]) : 0 ;
+check-equal var-subscript-range-pp : $(v3[2-4]) : 1 2 3 ;
+check-equal var-subscript-range-pm : $(v3[2--3]) : 1 2 3 4 5 6 7 8 ;
+check-equal var-subscript-range-pe : $(v3[2-]) : 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-ph : $(v3[2-20]) : 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-pl : $(v3[2--20]) : ;
+check-equal var-subscript-range-mp : $(v3[-3-10]) : 8 9 ;
+check-equal var-subscript-range-mm : $(v3[-4--2]) : 7 8 9 ;
+check-equal var-subscript-range-me : $(v3[-4-]) : 7 8 9 10 ;
+check-equal var-subscript-range-mh : $(v3[-4-20]) : 7 8 9 10 ;
+check-equal var-subscript-range-mh : $(v3[-4--20]) : ;
+check-equal var-subscript-range-0p : $(v3[0-2]) : 0 1 2 ;
+check-equal var-subscript-range-0m : $(v3[0--4]) : 0 1 2 3 4 5 6 7 8 ;
+check-equal var-subscript-range-0e : $(v3[0-]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-0h : $(v3[0-20]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-0l : $(v3[0--20]) : ;
+check-equal var-subscript-range-hp : $(v3[20-4]) : ;
+check-equal var-subscript-range-hm : $(v3[20--4]) : ;
+check-equal var-subscript-range-he : $(v3[20-]) : ;
+check-equal var-subscript-range-hh : $(v3[20-20]) : ;
+check-equal var-subscript-range-hl : $(v3[20--20]) : ;
+check-equal var-subscript-range-lp : $(v3[-13-4]) : 0 1 2 3 4 5 ;
+check-equal var-subscript-range-lm : $(v3[-13--4]) : 0 1 2 3 4 5 6 7 8 9 ;
+check-equal var-subscript-range-le : $(v3[-13-]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-lh : $(v3[-13-20]) : 0 1 2 3 4 5 6 7 8 9 10 ;
+check-equal var-subscript-range-ll : $(v3[-13--13]) : 0 ;
+check-equal var-subscript-range-empty : $(v3[4-3]) : ;
+
+}
+
+# Check rules
+
+{
+
+rule test-rule
+{
+ return $(<) - $(>) - $(1) - $(2) - $(3) - $(4) - $(5) - $(6) - $(7) - $(8) - $(9) - $(10) - $(11) - $(12) - $(13) - $(14) - $(15) - $(16) - $(17) - $(18) - $(19) ;
+}
+
+check-equal rule-arguments-numbered :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 - a2 - a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ;
+
+rule test-rule
+{
+ return $(<:L) - $(>:L) - $(1:L) - $(2:L) - $(3:L) - $(4:L) - $(5:L) - $(6:L) - $(7:L) - $(8:L) - $(9:L) - $(10:L) - $(11:L) - $(12:L) - $(13:L) - $(14:L) - $(15:L) - $(16:L) - $(17:L) - $(18:L) - $(19:L) ;
+}
+
+# behavior change
+check-equal rule-arguments-numbered-lower :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 - a2 - a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ;
+
+
+rule test-rule ( p1 : p2 : p3 : p4 : p5 : p6 : p7 : p8 : p9 :
+ p10 : p11 : p12 : p13 : p14 : p15 : p16 : p17 : p18 : p19 )
+
+
+{
+ return $(p1) - $(p2) - $(p3) - $(p4) - $(p5) - $(p6) - $(p7) - $(p8) - $(p9) - $(p10) - $(p11) - $(p12) - $(p13) - $(p14) - $(p15) - $(p16) - $(p17) - $(p18) - $(p19) ;
+}
+
+check-equal rule-arguments-named :
+ [ test-rule a1 : a2 : a3 : a4 : a5 : a6 : a7 : a8 : a9 : a10 : a11 : a12 : a13 : a14 : a15 : a16 : a17 : a18 : a19 ] :
+ a1 - a2 - a3 - a4 - a5 - a6 - a7 - a8 - a9 - a10 - a11 - a12 - a13 - a14 - a15 - a16 - a17 - a18 - a19 ;
+
+#
+# test rule indirection
+#
+rule select ( n list * )
+{
+ return $(list[$(n)]) ;
+}
+
+rule indirect1 ( rule + : args * )
+{
+ return [ $(rule) $(args) ] ;
+}
+
+check-equal rule-indirect-1 : [ indirect1 select 1 : a b c d e ] : a ;
+check-equal rule-indirect-2 : [ indirect1 select 2 : a b c d e ] : b ;
+
+x = reset ;
+rule reset-x ( new-value )
+{
+ x = $(new-value) ;
+}
+$(x)-x bar ; # invokes reset-x...
+check-equal rule-reset : $(x) : bar ; # which changes x
+
+rule bar-x ( new-value )
+{
+ mark-order r3 ;
+}
+
+# The arguments are evaluated in forward order
+# before the rule name
+$(x)-x [ mark-order r1 : [ reset-x reset ] ] : [ mark-order r2 ] ;
+check-order rule-order : r1 r2 ;
+
+}
+
+# Check append
+
+{
+
+local value = [ mark-order r1 : v1 v2 ] [ mark-order r2 : v3 v4 ] ;
+check-equal append : $(value) : v1 v2 v3 v4 ;
+check-order append-order : r1 r2 ;
+
+}
+
+# Check foreach
+
+{
+
+local v1 = 1 2 3 ;
+local x = old ;
+local result ;
+
+for local x in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-local-item : $(result) : 1 + 2 + 3 + ;
+check-equal foreach-local : $(x) : old ;
+
+result = ;
+
+for x in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-nonlocal-item : $(result) : 1 + 2 + 3 + ;
+check-equal foreach-nonlocal : $(x) : 3 ;
+
+rule call-foreach ( values * )
+{
+ for local x in $(values)
+ {
+ return $(x) ;
+ }
+}
+
+check-equal foreach-result : [ call-foreach 1 2 3 ] : ;
+
+result = ;
+local varname = x ;
+x = old ;
+
+for local $(varname) in $(v1)
+{
+ result += $(x) + ;
+}
+
+check-equal foreach-no-expand : $(result) : old + old + old + ;
+
+result = ;
+
+for local v1 in $(v1)
+{
+ result += $(v1) + ;
+}
+
+check-equal foreach-order : $(result) : 1 + 2 + 3 + ;
+
+}
+
+# Check if
+
+{
+
+if true
+{
+ mark-order r1 ;
+}
+
+check-order if-true : r1 ;
+
+if $(false)
+{
+ mark-order r1 ;
+}
+
+check-order if-false : ;
+
+if true
+{
+ mark-order r1 ;
+}
+else
+{
+ mark-order r2 ;
+}
+
+check-order if-else-true : r1 ;
+
+if $(false)
+{
+ mark-order r1 ;
+}
+else
+{
+ mark-order r2 ;
+}
+
+check-order if-else-false : r2 ;
+
+rule test-rule
+{
+ if true
+ {
+ return result ;
+ }
+}
+
+check-equal if-true-result : [ test-rule ] : result ;
+
+rule test-rule
+{
+ local idx = 1 2 ;
+ local values = true ;
+ while $(idx)
+ {
+ local v = $(values[$(idx[1])]) ;
+ idx = $(idx[2-]) ;
+ if $(v)
+ {
+ return result ;
+ }
+ }
+}
+
+check-equal if-false-result : [ test-rule ] : ;
+
+rule test-rule
+{
+ if true
+ {
+ return r1 ;
+ }
+ else
+ {
+ return r2 ;
+ }
+}
+
+check-equal if-else-true-result : [ test-rule ] : r1 ;
+
+rule test-rule
+{
+ if $(false)
+ {
+ return r1 ;
+ }
+ else
+ {
+ return r2 ;
+ }
+}
+
+check-equal if-else-false-result : [ test-rule ] : r2 ;
+
+}
+
+# Check the evaluation of conditions
+
+{
+
+local test-result ;
+local v1 = "" "" "" ;
+local v2 = ;
+local v3 = a b c ;
+local v4 = a b c d ;
+local v5 = a b d ;
+local v6 = "" "" "" d ;
+
+rule test-comparison ( id : equal less greater )
+{
+ check-equal $(id)-empty-1 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ;
+ check-equal $(id)-empty-2 : [ eval-$(id) $(v1) : $(v2) ] : $(equal) ;
+ check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(equal) ;
+ check-equal $(id)-less-1 : [ eval-$(id) $(v3) : $(v4) ] : $(less) ;
+ check-equal $(id)-less-2 : [ eval-$(id) $(v3) : $(v5) ] : $(less) ;
+ check-equal $(id)-less-3 : [ eval-$(id) $(v4) : $(v5) ] : $(less) ;
+ check-equal $(id)-greater-1 : [ eval-$(id) $(v4) : $(v3) ] : $(greater) ;
+ check-equal $(id)-greater-2 : [ eval-$(id) $(v5) : $(v3) ] : $(greater) ;
+ check-equal $(id)-greater-3 : [ eval-$(id) $(v5) : $(v4) ] : $(greater) ;
+}
+
+rule eval-lt ( lhs * : rhs * )
+{
+ if $(lhs) < $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison lt : false true false ;
+
+rule eval-gt ( lhs * : rhs * )
+{
+ if $(lhs) > $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison gt : false false true ;
+
+rule eval-le ( lhs * : rhs * )
+{
+ if $(lhs) <= $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison le : true true false ;
+
+rule eval-ge ( lhs * : rhs * )
+{
+ if $(lhs) >= $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison ge : true false true ;
+
+rule eval-eq ( lhs * : rhs * )
+{
+ if $(lhs) = $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison eq : true false false ;
+
+rule eval-ne ( lhs * : rhs * )
+{
+ if $(lhs) != $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-comparison ne : false true true ;
+
+rule eval-not-lt ( lhs * : rhs * )
+{
+ if ! ( $(lhs) < $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-lt : true false true ;
+
+rule eval-not-gt ( lhs * : rhs * )
+{
+ if ! ( $(lhs) > $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-gt : true true false ;
+
+rule eval-not-le ( lhs * : rhs * )
+{
+ if ! ( $(lhs) <= $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-le : false false true ;
+
+rule eval-not-ge ( lhs * : rhs * )
+{
+ if ! ( $(lhs) >= $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-ge : false true false ;
+
+rule eval-not-eq ( lhs * : rhs * )
+{
+ if ! ( $(lhs) = $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-eq : false true true ;
+
+rule eval-not-ne ( lhs * : rhs * )
+{
+ if ! ( $(lhs) != $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-comparison not-ne : true false false ;
+
+local v7 = a a a a a a ;
+local v8 = c b ;
+local v9 = c d b ;
+local v10 = c a b c c b a a a ;
+
+rule test-in ( id : subset not-subset )
+{
+ check-equal $(id)-0-0 : [ eval-$(id) $(v2) : $(v2) ] : $(subset) ;
+ check-equal $(id)-0-empty : [ eval-$(id) $(v2) : $(v1) ] : $(subset) ;
+ check-equal $(id)-empty-0 : [ eval-$(id) $(v1) : $(v2) ] : $(not-subset) ;
+ check-equal $(id)-equal : [ eval-$(id) $(v3) : $(v3) ] : $(subset) ;
+ check-equal $(id)-simple : [ eval-$(id) $(v3) : $(v4) ] : $(subset) ;
+ check-equal $(id)-extra : [ eval-$(id) $(v4) : $(v3) ] : $(not-subset) ;
+ check-equal $(id)-multiple : [ eval-$(id) $(v7) : $(v3) ] : $(subset) ;
+ check-equal $(id)-unordered : [ eval-$(id) $(v8) : $(v3) ] : $(subset) ;
+ check-equal $(id)-unordered-extra : [ eval-$(id) $(v9) : $(v3) ] : $(not-subset) ;
+ check-equal $(id)-unordered-multiple : [ eval-$(id) $(v10) : $(v3) ] : $(subset) ;
+}
+
+rule eval-in ( lhs * : rhs * )
+{
+ if $(lhs) in $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-in "in" : true false ;
+
+rule eval-not-in ( lhs * : rhs * )
+{
+ if ! ( $(lhs) in $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-in not-in : false true ;
+
+rule test-truth-table ( id : tt tf ft ff )
+{
+ check-equal $(id)-tt : [ eval-$(id) 1 : 1 ] : $(tt) ;
+ check-equal $(id)-tf : [ eval-$(id) 1 : ] : $(tf) ;
+ check-equal $(id)-ft : [ eval-$(id) : 1 ] : $(ft) ;
+ check-equal $(id)-ff : [ eval-$(id) : ] : $(ff) ;
+}
+
+rule eval-and ( lhs ? : rhs ? )
+{
+ if $(lhs) && $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table and : true false false false ;
+
+rule eval-or ( lhs ? : rhs ? )
+{
+ if $(lhs) || $(rhs) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table or : true true true false ;
+
+rule eval-not-and ( lhs ? : rhs ? )
+{
+ if ! ( $(lhs) && $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table not-and : false true true true ;
+
+rule eval-not-or ( lhs ? : rhs ? )
+{
+ if ! ( $(lhs) || $(rhs) ) { return true ; }
+ else { return false ; }
+}
+
+test-truth-table not-or : false false false true ;
+
+if [ mark-order r1 : test1 ] < [ mark-order r2 : test2 ] { }
+check-order lt-order : r1 r2 ;
+if [ mark-order r1 : test1 ] > [ mark-order r2 : test2 ] { }
+check-order gt-order : r1 r2 ;
+if [ mark-order r1 : test1 ] <= [ mark-order r2 : test2 ] { }
+check-order le-order : r1 r2 ;
+if [ mark-order r1 : test1 ] >= [ mark-order r2 : test2 ] { }
+check-order ge-order : r1 r2 ;
+if [ mark-order r1 : test1 ] = [ mark-order r2 : test2 ] { }
+check-order eq-order : r1 r2 ;
+if [ mark-order r1 : test1 ] != [ mark-order r2 : test2 ] { }
+check-order ne-order : r1 r2 ;
+if [ mark-order r1 : test1 ] in [ mark-order r2 : test2 ] { }
+check-order in-order : r1 r2 ;
+
+if [ mark-order r1 : test1 ] && [ mark-order r2 : test2 ] { }
+check-order and-order : r1 r2 ;
+if [ mark-order r1 ] && [ mark-order r2 : test2 ] { }
+check-order and-order-short-circuit : r1 ;
+
+if [ mark-order r1 ] || [ mark-order r2 : test2 ] { }
+check-order or-order : r1 r2 ;
+if [ mark-order r1 : test1 ] || [ mark-order r2 : test2 ] { }
+check-order or-order-short-circuit : r1 ;
+
+}
+
+# Check include
+
+{
+#FIXME:
+# plain include
+# include in module
+# include returns an empty list
+# rule arguments are available inside include
+}
+
+# Check local
+
+{
+
+local v1 = a b c ;
+local v2 = f g h ;
+
+{
+ local v1 ;
+ check-equal local-no-init : $(v1) : ;
+}
+
+check-equal local-restore : $(v1) : a b c ;
+
+{
+ local v1 = d e f ;
+ check-equal local-init : $(v1) : d e f ;
+}
+
+check-equal local-restore-init : $(v1) : a b c ;
+
+{
+ local v1 v2 ;
+ check-equal local-multiple-no-init : $(v1) - $(v2) : - ;
+}
+
+check-equal local-multiple-restore : $(v1) - $(v2) : a b c - f g h ;
+
+{
+ local v1 v2 = d e f ;
+ check-equal local-multiple-init : $(v1) - $(v2) : d e f - d e f ;
+}
+
+{
+ local v1 v1 = d e f ;
+ check-equal local-duplicate : $(v1) - $(v1) : d e f - d e f ;
+}
+
+check-equal local-duplicate-restore : $(v1) : a b c ;
+
+{
+ local [ mark-order r1 : v1 ] = [ mark-order r2 : d e f ] ;
+ check-order local-order : r1 r2 ;
+}
+
+}
+
+# Check module
+
+{
+ local var1 = root-module-var ;
+ module my_module
+ {
+ var1 = module-var ;
+ rule get ( )
+ {
+ return $(var1) ;
+ }
+ local rule not_really ( ) { return nothing ; }
+ }
+
+ 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 ;
+
+ IMPORT my_module : get : : module-get ;
+ check-equal module-rule-imort : [ module-get ] : module-var ;
+
+ IMPORT my_module : get : : module-get : LOCALIZE ;
+ check-equal module-rule-imort-localize : [ module-get ] : root-module-var ;
+
+}
+
+# Check class
+{
+#FIXME:
+# ...
+}
+
+# Check on
+
+{
+
+local target1 = test-on-target1 ;
+local target2 = test-on-target2 ;
+local targets = $(target1) $(target2) ;
+local v1 v2 v3 ;
+
+VAR on $(target1) = value1 ;
+V2 on $(target2) = value2 ;
+
+check-equal on-return : [ on $(target1) return $(VAR) ] : value1 ;
+
+rule test-rule
+{
+ return $(VAR) ;
+}
+
+check-equal on-rule : [ on $(target1) test-rule ] : value1 ;
+
+check-equal on-multiple : [ on $(targets) return $(V2) ] : ;
+
+rule test-rule
+{
+ on $(target1)
+ {
+ return $(VAR) ;
+ }
+}
+
+check-equal on-block : [ test-rule ] : value1 ;
+
+# FIXME: crazy implementation artifacts:
+
+v1 on test-on-target3 = x1 ;
+on test-on-target3
+{
+ v1 on test-on-target3 += x1 ;
+ v1 = y1 ;
+ v2 on test-on-target3 += x2 ;
+ v2 = y2 ;
+ v3 = y3 ;
+}
+
+check-equal on-swap-old1 : $(v1) : x1 ;
+check-equal on-swap-old2 : [ on test-on-target3 return $(v1) ] : y1 ;
+check-equal on-swap-new1 : $(v2) : x2 ;
+check-equal on-swap-new2 : [ on test-on-target3 return $(v2) ] : y2 ;
+check-equal on-no-swap : $(v3) : y3 ;
+
+}
+
+# Check rule
+
+{
+#FIXME:
+# argument order
+# expand rule name
+}
+
+# Check rules
+
+{
+#FIXME:
+}
+
+# Check set
+
+{
+local v1 ;
+local v2 ;
+local v3 ;
+local vars = v1 v2 v3 ;
+
+v1 = x1 ;
+check-equal set-set-empty : $(v1) : x1 ;
+v2 += x2 ;
+check-equal set-append-empty : $(v2) : x2 ;
+v3 ?= x3 ;
+check-equal set-default-empty : $(v3) : x3 ;
+
+v1 = y1 ;
+check-equal set-set-non-empty : $(v1) : y1 ;
+v2 += y2 ;
+check-equal set-append-non-empty : $(v2) : x2 y2 ;
+v3 ?= y3 ;
+check-equal set-default-non-empty : $(v3) : x3 ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) = z ;
+check-equal set-set-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) += z ;
+check-equal set-append-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = ;
+v2 = ;
+v3 = ;
+$(vars) ?= z ;
+check-equal set-default-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) = z ;
+check-equal set-set-non-empty-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) += z ;
+check-equal set-append-non-empty-group : $(v1) - $(v2) - $(v3) : x1 z - x2 z - x3 z ;
+
+v1 = x1 ;
+v2 = x2 ;
+v3 = x3 ;
+$(vars) ?= z ;
+check-equal set-default-non-empty-group : $(v1) - $(v2) - $(v3) : x1 - x2 - x3 ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) = z ;
+check-equal set-set-mixed-group : $(v1) - $(v2) - $(v3) : z - z - z ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) += z ;
+check-equal set-append-mixed-group : $(v1) - $(v2) - $(v3) : x1 z - z - x3 z ;
+
+v1 = x1 ;
+v2 = ;
+v3 = x3 ;
+$(vars) ?= z ;
+check-equal set-default-mixed-group : $(v1) - $(v2) - $(v3) : x1 - z - x3 ;
+
+vars = v1 v1 ;
+
+v1 = ;
+$(vars) = z ;
+check-equal set-set-duplicate-empty : $(v1) : z ;
+v1 = ;
+$(vars) += z ;
+check-equal set-append-duplicate-empty : $(v1) : z z ;
+v1 = ;
+$(vars) ?= z ;
+check-equal set-default-duplicate-empty : $(v1) : z ;
+
+v1 = x1 ;
+$(vars) = z ;
+check-equal set-set-duplicate-non-empty : $(v1) : z ;
+v1 = x1 ;
+$(vars) += z ;
+check-equal set-append-duplicate-non-empty : $(v1) : x1 z z ;
+v1 = x1 ;
+$(vars) ?= z ;
+check-equal set-default-duplicate-non-empty : $(v1) : x1 ;
+
+rule test-rule { v1 = x1 ; }
+check-equal set-set-result : [ test-rule ] : x1 ;
+rule test-rule { v1 += x1 ; }
+check-equal set-append-result : [ test-rule ] : x1 ;
+rule test-rule { v1 ?= x1 ; }
+check-equal set-default-result : [ test-rule ] : x1 ;
+
+[ mark-order r1 ] = [ mark-order r2 ] ;
+check-order set-set-order : r1 r2 ;
+[ mark-order r1 ] += [ mark-order r2 ] ;
+check-order set-append-order : r1 r2 ;
+[ mark-order r1 ] ?= [ mark-order r2 ] ;
+check-order set-default-order : r1 r2 ;
+
+}
+
+# Check setcomp
+
+{
+#FIXME
+# Expand arguments
+# Don't expand name
+}
+
+# Check setexec
+
+{
+#FIXME:
+# Don't expand name
+# Evaluate bindlist
+}
+
+# Check settings ;
+
+{
+
+local target1 = test-settings-target1 ;
+local target2 = test-settings-target2 ;
+local target3 = test-settings-target3 ;
+local targets = $(target2) $(target3) ;
+
+local vars = v1 v2 v3 ;
+
+v1 on $(target1) = x1 ;
+check-equal settings-set-empty : [ on $(target1) return $(v1) ] : x1 ;
+v2 on $(target1) += x2 ;
+check-equal settings-append-empty : [ on $(target1) return $(v2) ] : x2 ;
+v3 on $(target1) ?= x3 ;
+check-equal settings-default-empty : [ on $(target1) return $(v3) ] : x3 ;
+
+v1 on $(target1) = y1 ;
+check-equal settings-set-non-empty : [ on $(target1) return $(v1) ] : y1 ;
+v2 on $(target1) += y2 ;
+check-equal settings-append-non-empty : [ on $(target1) return $(v2) ] : x2 y2 ;
+v3 on $(target1) ?= y3 ;
+check-equal settings-default-non-empty : [ on $(target1) return $(v3) ] : x3 ;
+
+$(vars) on setting-target2 = z ;
+check-equal settings-set-empty-group : [ on setting-target2 return $(v1) ] - [ on setting-target2 return $(v2) ] - [ on setting-target2 return $(v3) ] : z - z - z ;
+
+$(vars) on setting-target3 += z ;
+check-equal settings-append-empty-group : [ on setting-target3 return $(v1) ] - [ on setting-target3 return $(v2) ] - [ on setting-target3 return $(v3) ] : z - z - z ;
+
+$(vars) on setting-target4 ?= z ;
+check-equal settings-default-empty-group : [ on setting-target4 return $(v1) ] - [ on setting-target4 return $(v2) ] - [ on setting-target4 return $(v3) ] : z - z - z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) = z ;
+check-equal settings-set-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : z - z - z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) += z ;
+check-equal settings-append-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 z - x2 z - x3 z ;
+
+v1 on $(target1) = x1 ;
+v2 on $(target1) = x2 ;
+v3 on $(target1) = x3 ;
+$(vars) on $(target1) ?= z ;
+check-equal settings-default-non-empty-group : [ on $(target1) return $(v1) ] - [ on $(target1) return $(v2) ] - [ on $(target1) return $(v3) ] : x1 - x2 - x3 ;
+
+v1 on setting-target5 = x1 ;
+v3 on setting-target5 = x3 ;
+$(vars) on setting-target5 = z ;
+check-equal settings-set-mixed-group : [ on setting-target5 return $(v1) ] - [ on setting-target5 return $(v2) ] - [ on setting-target5 return $(v3) ] : z - z - z ;
+
+v1 on setting-target6 = x1 ;
+v3 on setting-target6 = x3 ;
+$(vars) on setting-target6 += z ;
+check-equal settings-append-mixed-group : [ on setting-target6 return $(v1) ] - [ on setting-target6 return $(v2) ] - [ on setting-target6 return $(v3) ] : x1 z - z - x3 z ;
+
+v1 on setting-target7 = x1 ;
+v3 on setting-target7 = x3 ;
+$(vars) on setting-target7 ?= z ;
+check-equal settings-default-mixed-group : [ on setting-target7 return $(v1) ] - [ on setting-target7 return $(v2) ] - [ on setting-target7 return $(v3) ] : x1 - z - x3 ;
+
+vars = v1 v1 ;
+
+$(vars) on setting-target8 = z ;
+check-equal settings-set-duplicate-empty : [ on setting-target8 return $(v1) ] : z ;
+$(vars) on setting-target9 += z ;
+check-equal settings-append-duplicate-empty : [ on setting-target9 return $(v1) ] : z z ;
+$(vars) on setting-target10 ?= z ;
+check-equal settings-default-duplicate-empty : [ on setting-target10 return $(v1) ] : z ;
+
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) = z ;
+check-equal settings-set-duplicate-non-empty : [ on $(target1) return $(v1) ] : z ;
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) += z ;
+check-equal settings-append-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 z z ;
+v1 on $(target1) = x1 ;
+$(vars) on $(target1) ?= z ;
+check-equal settings-default-duplicate-non-empty : [ on $(target1) return $(v1) ] : x1 ;
+
+v1 on $(target1) = ;
+v1 on $(target1) ?= z ;
+check-equal settings-default-set-but-empty : [ on $(target1) return $(v1) ] : ;
+
+v1 on $(targets) = multi ;
+check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi - multi ;
+v2 on $(targets) += multi ;
+check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi - multi ;
+v3 on $(targets) ?= multi ;
+check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ;
+
+v1 on $(targets) = multi2 ;
+check-equal settings-set-multi-empty : [ on $(target2) return $(v1) ] - [ on $(target3) return $(v1) ] : multi2 - multi2 ;
+v2 on $(targets) += multi2 ;
+check-equal settings-append-multi-empty : [ on $(target2) return $(v2) ] - [ on $(target3) return $(v2) ] : multi multi2 - multi multi2 ;
+v3 on $(targets) ?= multi2 ;
+check-equal settings-default-multi-empty : [ on $(target2) return $(v3) ] - [ on $(target3) return $(v3) ] : multi - multi ;
+
+rule test-rule { v1 on $(target1) = x1 ; }
+check-equal settings-set-result : [ test-rule ] : x1 ;
+rule test-rule { v1 on $(target1) += x1 ; }
+check-equal settings-append-result : [ test-rule ] : x1 ;
+rule test-rule { v1 on $(target1) ?= x1 ; }
+check-equal settings-default-result : [ test-rule ] : x1 ;
+
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] = [ mark-order r2 : value ] ;
+check-order settings-set-order : r1 r2 r3 ;
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] += [ mark-order r2 : value ] ;
+check-order settings-append-order : r1 r2 r3 ;
+[ mark-order r1 : var ] on [ mark-order r3 : $(target1) ] ?= [ mark-order r2 : value ] ;
+check-order settings-default-order : r1 r2 r3 ;
+
+}
+
+# Check switch
+
+{
+
+local pattern = * ;
+
+switch value
+{
+ case * : mark-order r1 ;
+}
+
+check-order switch-match-any : r1 ;
+
+switch value
+{
+ case v2 : mark-order r1 ;
+}
+
+check-order switch-no-match : ;
+
+switch value
+{
+ case $(pattern) : mark-order r1 ;
+}
+
+check-order switch-no-expand : ;
+
+switch value
+{
+ case value : mark-order r1 ;
+ case * : mark-order r2 ;
+}
+
+check-order switch-match-several : r1 ;
+
+rule test-rule ( value )
+{
+ switch $(value)
+ {
+ case value : return 1 ;
+ }
+}
+
+check-equal switch-result-match : [ test-rule value ] : 1 ;
+check-equal switch-result-match : [ test-rule v1 ] : ;
+
+switch $()
+{
+ case "" : mark-order r1 ;
+ case * : mark-order r2 ;
+}
+
+check-order switch-empty : r1 ;
+
+local values = v1 v2 v3 ;
+switch $(values)
+{
+ case v1 : mark-order r1 ;
+ case v2 : mark-order r2 ;
+ case v3 : mark-order r3 ;
+}
+
+check-order switch-multiple : r1 ;
+
+# Test glob matching
+
+switch value { case * : mark-order r1 ; }
+check-order switch-glob-star : r1 ;
+
+switch value { case va*e : mark-order r1 ; }
+check-order switch-glob-star-1 : r1 ;
+
+switch value { case *a* : mark-order r1 ; }
+check-order switch-glob-star-2 : r1 ;
+
+switch value { case *a*ue* : mark-order r1 ; }
+check-order switch-glob-star-3 : r1 ;
+
+switch value { case *[eaiou]*ue : mark-order r1 ; }
+check-order switch-glob-group : r1 ;
+
+switch value { case *[eaiou]ue : mark-order r1 ; }
+check-order switch-glob-group-fail : ;
+
+switch value { case ?a?ue : mark-order r1 ; }
+check-order switch-glob-any : r1 ;
+
+switch value { case ?lue : mark-order r1 ; }
+check-order switch-glob-any-fail : ;
+
+}
+
+# Test while
+
+{
+
+local value = 1 2 3 ;
+
+while $(value)
+{
+ mark-order r$(value[1]) ;
+ value = $(value[2-]) ;
+}
+
+check-order while-exec : r1 r2 r3 ;
+
+rule test-rule
+{
+ local value = 1 2 3 ;
+ while $(value)
+ {
+ value = $(value[2-]) ;
+ return x ;
+ }
+}
+
+check-equal while-result : [ test-rule ] : x ;
+
+rule test-rule
+{
+ local value = 1 2 ;
+ while $(value)
+ {
+ value = $(value[2-]) ;
+ local inner = $(value) ;
+ while $(inner)
+ {
+ inner = $(inner[2-]) ;
+ return x ;
+ }
+ }
+}
+
+check-equal while-result-2 : [ test-rule ] : ;
+
+}
+
+#
+# test CALLER_MODULE and backtrace
+#
+
+{
+ local base = [ BACKTRACE ] ;
+ base = $(base[2]) ;
+ rule backtrace ( )
+ {
+ local bt = [ BACKTRACE ] ;
+ check-equal backtrace-1-file : $(bt) :
+ test.jam [ CALC $(base) + 4 ] "" backtrace
+ test.jam [ CALC $(base) + 28 ] module2. module2.f
+ test.jam [ CALC $(base) + 19 ] module1. module1.f
+ test.jam [ CALC $(base) + 32 ] "" "module scope"
+ ;
+ }
+ module module1
+ {
+ IMPORT_MODULE module2 : module1 ;
+ rule f ( )
+ {
+ local m = [ CALLER_MODULE ] ;
+ check-equal caller-module-root : $(m) ;
+ module2.f ;
+ }
+ }
+ module module2
+ {
+ rule f ( )
+ {
+ local m = [ CALLER_MODULE ] ;
+ check-equal caller-module : module1 : $(m) ;
+ backtrace ;
+ }
+ }
+ IMPORT_MODULE module1 ;
+ module1.f ;
+}
+
+
+# Test NORMALIZE_PATH
+
+{
+check-equal normalize-path : "." : [ NORMALIZE_PATH ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "." ] ;
+check-equal normalize-path : ".." : [ NORMALIZE_PATH ".." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "//" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "//\\\\//\\\\" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/./" ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\///.///\\\\\\" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "./././././." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/./././././." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////" ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////././." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo\\\\/////./././" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo////.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "///foo/\\\\/.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "\\\\\\foo\\//\\.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/./.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/././././.." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/./././bar/./././.././././baz/./././.." ] ;
+check-equal normalize-path : "/foo" : [ NORMALIZE_PATH "/foo/./././bar/./././.././././baz/./././.." ] ;
+check-equal normalize-path : "foo" : [ NORMALIZE_PATH "foo/./././bar/./././////.././././baz/./././.." ] ;
+check-equal normalize-path : "/foo" : [ NORMALIZE_PATH "/foo/./././bar/./././////.././././baz/./././.." ] ;
+check-equal normalize-path : ".." : [ NORMALIZE_PATH "./.." ] ;
+check-equal normalize-path : ".." : [ NORMALIZE_PATH "././././.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "../.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "./../.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "././././../.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "./.././././.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "././././.././././.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "..//\\\\\\//.." ] ;
+check-equal normalize-path : "../.." : [ NORMALIZE_PATH "../..\\\\/\\\\" ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo/../bar/../baz/.." ] ;
+check-equal normalize-path : "." : [ NORMALIZE_PATH "foo////..////bar////.//////.////../baz/.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/foo/../bar/../baz/.." ] ;
+check-equal normalize-path : "/" : [ NORMALIZE_PATH "/foo////..////bar////.//////.////../baz/.." ] ;
+
+# Invalid rooted paths with leading dotdots.
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../" ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "//\\\\//\\\\/.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "\\\\//\\\\//\\.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../../.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/foo/bar/../baz/../../.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../for/././../././bar/././../././.." ] ;
+check-equal normalize-path-invalid : : [ NORMALIZE_PATH "/../foo/bar" ] ;
+
+}
+
+# Test W32_GETREGNAMES
+
+{
+
+if $(NT)
+{
+ local sound = "Beep" "ExtendedSounds" ;
+ 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) ;
+
+ 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 r4 = [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ;
+ check-equal w32_getregnames : $(CurrentControlSet:L) : $(r4:L) ;
+}
+
+}
+
+# Test SHELL
+
+{
+
+local c = "echo value" ;
+
+check-equal shell : "value\n" : [ SHELL $(c) ] ;
+check-equal shell : "" : [ SHELL $(c) : no-output ] ;
+check-equal shell : "value\n" 0 : [ SHELL $(c) : exit-status ] ;
+check-equal shell : "" 0 : [ SHELL $(c) : no-output : exit-status ] ;
+check-equal command : "value\n" : [ COMMAND $(c) ] ;
+check-equal command : "" : [ COMMAND $(c) : no-output ] ;
+check-equal command : "value\n" 0 : [ COMMAND $(c) : exit-status ] ;
+check-equal command : "" 0 : [ COMMAND $(c) : no-output : exit-status ] ;
+
+}
+
+# Test SUBST
+
+{
+
+# Check that unmatched subst returns an empty list
+check-equal subst-nomatch : [ SUBST "abc" "d+" x ] : ;
+
+# 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 ;
+
+}
+
+# Test summary
+
+if $(failed) = 0
+{
+ status = 0 ;
+}
+else
+{
+ status = 1 ;
+}
+
+EXIT $(passed) passed $(failed) failed : $(status) ;
diff --git a/tools/build/v2/test/core_action_status.py b/tools/build/v2/test/core_action_status.py
new file mode 100755
index 0000000000..75dbdf5391
--- /dev/null
+++ b/tools/build/v2/test/core_action_status.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+
+# 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)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.write("file.jam", """
+ actions quietly .a. { $(ACTION) }
+
+ rule .a.
+ {
+ DEPENDS $(<) : $(>) ;
+ }
+
+ NOTFILE subtest ;
+ .a. subtest_a : subtest ;
+ DEPENDS all : subtest_a ;
+""")
+
+t.run_build_system("-ffile.jam -sACTION=invalid", status=1)
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/actions_quietly.jam b/tools/build/v2/test/core_actions_quietly.py
index e7b9ad86cb..e8d5d43413 100644..100755
--- a/tools/build/v2/test/engine/actions_quietly.jam
+++ b/tools/build/v2/test/core_actions_quietly.py
@@ -1,12 +1,34 @@
-#~ 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)
+#!/usr/bin/python
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing \"actions quietly\"... ;
+# 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)
- assert "...found 4 targets...
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+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 ;
+""")
+
+t.run_build_system("-ffile.jam -d2", stdout="""...found 4 targets...
...updating 2 targets...
.a. subtest_a
@@ -27,29 +49,11 @@ echo [subtest_b] 2
[subtest_b] 1
[subtest_b] 2
...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f actions_quietly.jam -sBJAM_SUBTEST=1 -d2" ] ;
+""")
- assert "...found 4 targets...
+t.run_build_system("-ffile.jam -d1", stdout="""...found 4 targets...
...updating 2 targets...
...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f actions_quietly.jam -sBJAM_SUBTEST=1" ] ;
-}
-else
-{
- 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 ;
-}
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_arguments.py b/tools/build/v2/test/core_arguments.py
new file mode 100755
index 0000000000..5a1bc9b655
--- /dev/null
+++ b/tools/build/v2/test/core_arguments.py
@@ -0,0 +1,109 @@
+#!/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("echo_args.jam", """
+rule echo_args ( a b ? c ? : d + : e * )
+{
+ ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) ;
+}
+
+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]) ;
+}
+""")
+
+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");
+
+# 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=");
+
+# 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=");
+
+# Check modifier '*'
+
+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");
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_at_file.py b/tools/build/v2/test/core_at_file.py
new file mode 100755
index 0000000000..71f1bbcebe
--- /dev/null
+++ b/tools/build/v2/test/core_at_file.py
@@ -0,0 +1,75 @@
+#!/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)
+
+
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+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.expect_addition("on1 on2 .txt")
+t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True)
+
+t.rm(".")
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+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.expect_addition("on1 on2 .txt")
+t.expect_content("on1 on2 .txt", " test -DM1 -DM2", True)
+
+t.rm(".")
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+file = "@($(STDOUT):E= test -D$(contents)\n)" ;
+
+actions run {
+$(file)
+}
+
+run all ;
+""")
+
+t.run_build_system("-ffile.jam -d1")
+t.expect_output_line(" test -DM1 -DM2")
+
+t.rm(".")
+
+t.write("file.jam", """
+name = n1 n2 ;
+contents = M1 M2 ;
+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.cleanup()
diff --git a/tools/build/v2/test/check-bindrule.jam b/tools/build/v2/test/core_bindrule.py
index f8eb986e39..d5aaa7fc53 100644..100755
--- a/tools/build/v2/test/check-bindrule.jam
+++ b/tools/build/v2/test/core_bindrule.py
@@ -1,8 +1,18 @@
+#!/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)
-# This rule establishes a dependency, with no special build actions
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("subdir1/file-to-bind", "# This file intentionally left blank")
+
+t.write("file.jam", """
rule do-nothing ( target : source )
{
DEPENDS $(target) : $(source) ;
@@ -27,3 +37,11 @@ rule bind-rule ( target : path )
}
DEPENDS all : fake-target ;
+""")
+
+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)
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_import_module.py b/tools/build/v2/test/core_import_module.py
index fab209e4cb..2ab5942415 100644
--- a/tools/build/v2/test/core_import_module.py
+++ b/tools/build/v2/test/core_import_module.py
@@ -15,6 +15,11 @@ module a
{
ECHO R1 ;
}
+
+ local rule l1 ( )
+ {
+ ECHO A.L1 ;
+ }
}
module a2
{
@@ -25,6 +30,11 @@ module a2
}
IMPORT a2 : r2 : : a2.r2 ;
+rule a.l1 ( )
+{
+ ECHO L1 ;
+}
+
module b
{
IMPORT_MODULE a : b ;
@@ -34,6 +44,11 @@ module b
a.r1 ;
# Call rule in global scope
a2.r2 ;
+ # Call rule in global scope. Doesn't find local rule
+ a.l1 ;
+ # Make l1 visible
+ EXPORT a : l1 ;
+ a.l1 ;
}
}
@@ -57,6 +72,8 @@ do-nothing all ;
t.run_build_system("-fcode", stdout="""R1
R2
+L1
+A.L1
CTEST
""")
diff --git a/tools/build/v2/test/project-test1/dir2/jamfile.jam b/tools/build/v2/test/core_language.py
index 8d1c48b65b..42b4366894 100644..100755
--- a/tools/build/v2/test/project-test1/dir2/jamfile.jam
+++ b/tools/build/v2/test/core_language.py
@@ -1,9 +1,14 @@
-# Copyright 2004 Rene Rivera
+#!/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)
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.set_tree("core-language")
+t.run_build_system(extra_args="-ftest.jam")
-project /cool-library
- : requirements <include>/home/ghost/build/boost-cvs
- ;
+t.cleanup()
diff --git a/tools/build/v2/test/test_nt_line_length.jam b/tools/build/v2/test/core_nt_line_length.py
index bc003964e3..809c5e1ec5 100644..100755
--- a/tools/build/v2/test/test_nt_line_length.jam
+++ b/tools/build/v2/test/core_nt_line_length.py
@@ -1,11 +1,16 @@
+#!/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)
-# Test that the patch which allows long command-lines in actions on NT is
-# working. For reasons of backward-compatibility, this patch requires that the
-# action fits on a single command-line, and that the JAMSHELL variable on the
-# target being built is set to "%".
+import BoostBuild
+import os
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("file.jam", """
if $(NT)
{
#
@@ -37,3 +42,11 @@ if $(NT)
do_echo line_length_test ;
}
+else
+{
+ NOCARE all ;
+}
+""")
+t.run_build_system("-ffile.jam")
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/option_d2.jam b/tools/build/v2/test/core_option_d2.py
index 6dee8f47e7..0784954020 100644..100755
--- a/tools/build/v2/test/engine/option_d2.jam
+++ b/tools/build/v2/test/core_option_d2.py
@@ -1,12 +1,39 @@
-#~ 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)
+#!/usr/bin/python
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -d2 option... ;
+# 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)
- assert "...found 4 targets...
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+timeout /T %1 /NOBREAK >nul
+""")
+
+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 ;
+""")
+
+t.run_build_system("-ffile.jam -d2", stdout="""...found 4 targets...
...updating 2 targets...
.a. subtest_a
@@ -27,24 +54,6 @@ echo [subtest_b] 2
[subtest_b] 1
[subtest_b] 2
...updated 2 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f option_d2.jam -sBJAM_SUBTEST=1 -d2" ] ;
-}
-else
-{
- 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 ;
-}
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_option_l.py b/tools/build/v2/test/core_option_l.py
new file mode 100755
index 0000000000..e05e9a9517
--- /dev/null
+++ b/tools/build/v2/test/core_option_l.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+
+# 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)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@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
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
+
+if $(NT)
+{
+ SLEEP = @call sleep.bat ;
+}
+else
+{
+ SLEEP = sleep ;
+}
+
+actions .a. {
+echo 001
+$(SLEEP) 4
+echo 002
+}
+
+.a. sleeper ;
+
+DEPENDS all : sleeper ;
+""")
+
+t.run_build_system("-ffile.jam -d1 -l2", status=1)
+
+t.expect_output_line("2 second time limit exceeded")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_option_n.py b/tools/build/v2/test/core_option_n.py
new file mode 100755
index 0000000000..3b91d8e632
--- /dev/null
+++ b/tools/build/v2/test/core_option_n.py
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+# 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)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+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 ;
+""")
+
+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()
diff --git a/tools/build/v2/test/engine/parallel_actions.jam b/tools/build/v2/test/core_parallel_actions.py
index adcd1ad855..dedf9b1183 100644..100755
--- a/tools/build/v2/test/engine/parallel_actions.jam
+++ b/tools/build/v2/test/core_parallel_actions.py
@@ -1,60 +1,34 @@
-#~ 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)
+#!/usr/bin/python
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -jN parallel execution of actions... ;
+# 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)
- assert "...found 12 targets...
-...updating 8 targets...
-sleeper 1.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 2.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 3.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 4.a
-[.a] 0
-[.a] 1
-[.a] 2
-sleeper 1.b
-[.b] 0
-[.b] 1
-[.b] 2
-sleeper 2.b
-[.b] 0
-[.b] 1
-[.b] 2
-sleeper 3.b
-[.b] 0
-[.b] 1
-[.b] 2
-sleeper 4.b
-[.b] 0
-[.b] 1
-[.b] 2
-...updated 8 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f parallel_actions.jam -sBJAM_SUBTEST=1 -j4" ] ;
-}
-else
-{
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@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
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
if $(NT)
{
actions sleeper
{
echo [$(<:S)] 0
-sleep 1
+@call sleep.bat 1
echo [$(<:S)] 1
-sleep 1
+@call sleep.bat 1
echo [$(<:S)] 2
-sleep $(<:B)
+@call sleep.bat $(<:B)
}
}
else
@@ -88,4 +62,43 @@ sleep $(<:B)
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...
+...updating 8 targets...
+sleeper 1.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 2.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 3.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 4.a
+[.a] 0
+[.a] 1
+[.a] 2
+sleeper 1.b
+[.b] 0
+[.b] 1
+[.b] 2
+sleeper 2.b
+[.b] 0
+[.b] 1
+[.b] 2
+sleeper 3.b
+[.b] 0
+[.b] 1
+[.b] 2
+sleeper 4.b
+[.b] 0
+[.b] 1
+[.b] 2
+...updated 8 targets...
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_parallel_multifile_actions_1.py b/tools/build/v2/test/core_parallel_multifile_actions_1.py
new file mode 100755
index 0000000000..9d995dbca4
--- /dev/null
+++ b/tools/build/v2/test/core_parallel_multifile_actions_1.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+
+# 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)
+
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@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
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
+
+ if $(NT)
+ {
+ SLEEP = @call sleep.bat ;
+ }
+ else
+ {
+ SLEEP = sleep ;
+ }
+
+ actions .gen. {
+echo 001
+$(SLEEP) 4
+echo 002
+}
+ rule .use.1 { DEPENDS $(<) : $(>) ; }
+ actions .use.1 {
+echo 003
+}
+ 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 ;
+""")
+
+t.run_build_system("-ffile.jam -j2", stdout="""...found 6 targets...
+...updating 4 targets...
+.gen. g1.generated
+001
+002
+.use.1 u1.user
+003
+.use.2 u2.user
+004
+...updated 4 targets...
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/engine/parallel_multifile_actions_2.jam b/tools/build/v2/test/core_parallel_multifile_actions_2.py
index a85cf63fdb..aae0fe26e6 100644..100755
--- a/tools/build/v2/test/engine/parallel_multifile_actions_2.jam
+++ b/tools/build/v2/test/core_parallel_multifile_actions_2.py
@@ -1,6 +1,9 @@
+#!/usr/bin/python
+
# Copyright 2008 Jurko Gospodnetic, 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 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)
# 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
@@ -14,24 +17,33 @@
# 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.
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -jN parallel execution of multi-file actions - 2... ;
+import BoostBuild
+
+t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+t.write("sleep.bat","""@setlocal
+@echo off
+@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
+@endlocal
+@exit /B 0
+""")
+
+t.write("file.jam", """
+
+ if $(NT)
+ {
+ SLEEP = @call sleep.bat ;
+ }
+ else
+ {
+ SLEEP = sleep ;
+ }
- assert "...found 4 targets...
-...updating 3 targets...
-link dll
-001 - linked
-install installed_dll
-002 - installed
-...updated 3 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f parallel_multifile_actions_2.jam -sBJAM_SUBTEST=1 -j2" ] ;
-}
-else
-{
actions link
{
- sleep 1
+ $(SLEEP) 1
echo 001 - linked
}
@@ -46,4 +58,15 @@ else
DEPENDS installed_dll : dll ;
DEPENDS all : lib installed_dll ;
-}
+""")
+
+t.run_build_system("-ffile.jam -j2", stdout="""...found 4 targets...
+...updating 3 targets...
+link dll
+001 - linked
+install installed_dll
+002 - installed
+...updated 3 targets...
+""")
+
+t.cleanup()
diff --git a/tools/build/v2/test/core_update_now.py b/tools/build/v2/test/core_update_now.py
new file mode 100755
index 0000000000..d31a8c5607
--- /dev/null
+++ b/tools/build/v2/test/core_update_now.py
@@ -0,0 +1,198 @@
+#!/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)
+
+import BoostBuild
+import os
+
+def basic():
+ # Basic test
+
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+do-print target1 ;
+
+UPDATE_NOW target1 ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system("-ffile.jam", stdout="""...found 1 target...
+...updating 1 target...
+do-print target1
+updating target1
+...updated 1 target...
+...found 1 target...
+""")
+
+ t.cleanup()
+
+def ignore_minus_n():
+ # ignore-minus-n
+
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+do-print target1 ;
+
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+...updating 1 target...
+do-print target1
+
+ echo updating target1
+
+updating target1
+...updated 1 target...
+...found 1 target...
+""")
+
+ t.cleanup()
+
+def failed_target():
+
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions fail
+{
+ exit 1
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+fail target1 ;
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target2 ;
+do-print target2 ;
+DEPENDS target2 : target1 ;
+
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 target2 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+...updating 1 target...
+fail target1
+
+ exit 1
+
+...failed fail target1...
+...failed updating 1 target...
+...found 2 targets...
+...updating 1 target...
+do-print target2
+
+ echo updating target2
+
+...updated 1 target...
+""")
+
+ t.cleanup()
+
+def missing_target():
+ t = BoostBuild.Tester(pass_toolset=0, pass_d0=False)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target2 ;
+do-print target2 ;
+DEPENDS target2 : target1 ;
+
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 target2 ;
+""")
+
+ 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...
+...can't make 1 target...
+""")
+
+ 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)
+
+ t.write("file.jam", """
+
+actions do-print
+{
+ echo updating $(<)
+}
+
+NOTFILE target1 ;
+ALWAYS target1 ;
+do-print target1 ;
+
+UPDATE_NOW target1 ;
+UPDATE_NOW target1 : : ignore-minus-n ;
+UPDATE_NOW target1 : : ignore-minus-n ;
+
+DEPENDS all : target1 ;
+""")
+
+ t.run_build_system("-ffile.jam -n", stdout="""...found 1 target...
+...updating 1 target...
+do-print target1
+
+ echo updating target1
+
+...updated 1 target...
+do-print target1
+
+ echo updating target1
+
+updating target1
+...updated 1 target...
+...found 1 target...
+""")
+
+ t.cleanup()
+
+basic()
+ignore_minus_n()
+failed_target()
+missing_target()
+build_once()
diff --git a/tools/build/v2/test/direct-request-test/a.cpp b/tools/build/v2/test/direct-request-test/a.cpp
deleted file mode 100644
index cb97ea0c3e..0000000000
--- a/tools/build/v2/test/direct-request-test/a.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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)
-//
-// http://www.boost.org
-//
-
-void
-# ifdef _WIN32
-__declspec(dllimport)
-# endif
-foo();
-
-int main()
-{
- foo();
-}
diff --git a/tools/build/v2/test/direct-request-test/b.cpp b/tools/build/v2/test/direct-request-test/b.cpp
deleted file mode 100644
index 22dc6bb5d8..0000000000
--- a/tools/build/v2/test/direct-request-test/b.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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)
-//
-// http://www.boost.org
-//
-
-// This file will declare 'foo' is 'MACROS' is defined.
-
-#ifdef MACROS
-void
-# ifdef _WIN32
-__declspec(dllexport)
-# endif
-foo() {}
-#endif
-
-# ifdef _WIN32
-int __declspec(dllexport) force_implib_creation;
-# endif
diff --git a/tools/build/v2/test/direct-request-test/b_inverse.cpp b/tools/build/v2/test/direct-request-test/b_inverse.cpp
deleted file mode 100644
index 5068f6118a..0000000000
--- a/tools/build/v2/test/direct-request-test/b_inverse.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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)
-//
-// http://www.boost.org
-//
-
-// This file will declare 'foo' is 'MACROS' is NOT defined.
-
-#ifndef MACROS
-void
-# ifdef _WIN32
-__declspec(dllexport)
-# endif
-foo() {}
-#endif
-
-# ifdef _WIN32
-int __declspec(dllexport) force_implib_creation;
-# endif
diff --git a/tools/build/v2/test/direct-request-test/jamfile.jam b/tools/build/v2/test/direct-request-test/jamfile.jam
deleted file mode 100644
index f57874d3f0..0000000000
--- a/tools/build/v2/test/direct-request-test/jamfile.jam
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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)
-
-
-# This will link correctly only if symbol MACROS is defined when compiling
-# b.cpp. However, this is only possible if that symbol is requested
-# on command line and b.cpp is compiled with directly requested
-# properties.
-
-exe a : a.cpp b ;
-
-lib b : b.cpp ;
diff --git a/tools/build/v2/test/direct-request-test/jamfile2.jam b/tools/build/v2/test/direct-request-test/jamfile2.jam
deleted file mode 100644
index bc7e1bc74b..0000000000
--- a/tools/build/v2/test/direct-request-test/jamfile2.jam
+++ /dev/null
@@ -1,9 +0,0 @@
-
-# This will link correctly only if symbol MACROS is not defined when
-# compiling b.cpp. This tests if direct build request
-# 'release <define>MACROS' to 'b' does not add 'MACROS' when 'b'
-# is compiled with 'debug' -- the version needed by 'a'.
-
-exe a : a.cpp b : <variant>debug ;
-
-lib b : b.cpp ; \ No newline at end of file
diff --git a/tools/build/v2/test/direct-request-test/jamroot.jam b/tools/build/v2/test/direct-request-test/jamroot.jam
deleted file mode 100644
index 845aca8545..0000000000
--- a/tools/build/v2/test/direct-request-test/jamroot.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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)
-
-
-import gcc ;
diff --git a/tools/build/v2/test/direct_request_test.py b/tools/build/v2/test/direct_request_test.py
index 000d15b64d..32121f1d75 100644
--- a/tools/build/v2/test/direct_request_test.py
+++ b/tools/build/v2/test/direct_request_test.py
@@ -4,9 +4,42 @@ import BoostBuild
t = BoostBuild.Tester()
-
# First check some startup.
-t.set_tree("direct-request-test")
+
+t.write("jamroot.jam", "")
+
+t.write("jamfile.jam", """
+exe a : a.cpp b ;
+lib b : b.cpp ;
+""")
+
+t.write("a.cpp", """
+void
+# ifdef _WIN32
+__declspec(dllimport)
+# endif
+foo();
+
+int main()
+{
+ foo();
+}
+""")
+
+t.write("b.cpp", """
+#ifdef MACROS
+void
+# ifdef _WIN32
+__declspec(dllexport)
+# endif
+foo() {}
+#endif
+
+# ifdef _WIN32
+int __declspec(dllexport) force_implib_creation;
+# endif
+""")
+
t.run_build_system(extra_args="define=MACROS")
t.expect_addition("bin/$toolset/debug/"
* (BoostBuild.List("a.obj b.obj b.dll a.exe")))
@@ -19,11 +52,11 @@ t.expect_addition("bin/$toolset/debug/"
* (BoostBuild.List("a.obj b.obj b.dll a.exe")))
-# When building release version, the 'define' should not apply: we will have
-# direct build request 'release <define>MACROS' and a real build property
-# 'debug'.
-t.copy("jamfile2.jam", "jamfile.jam")
-t.copy("b_inverse.cpp", "b.cpp")
+# When building 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")
diff --git a/tools/build/v2/test/echo_args.jam b/tools/build/v2/test/echo_args.jam
deleted file mode 100644
index 0f6956e462..0000000000
--- a/tools/build/v2/test/echo_args.jam
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2001 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)
-
-rule echo_args ( a b ? c ? : d + : e * )
-{
- ECHO a= $(a) b= $(b) c= $(c) ":" d= $(d) ":" e= $(e) ;
-}
-
-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]) ;
-}
-
diff --git a/tools/build/v2/test/empty.jam b/tools/build/v2/test/empty.jam
deleted file mode 100644
index c6220580ca..0000000000
--- a/tools/build/v2/test/empty.jam
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2001 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)
-
-# This file is empty; it just suppresses warnings
diff --git a/tools/build/v2/test/engine/README.txt b/tools/build/v2/test/engine/README.txt
deleted file mode 100644
index c38701fb8a..0000000000
--- a/tools/build/v2/test/engine/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-
-This directory contains tests for the update engine of
-Boost.Build. They presently are not integrated with
-the Python based test system and must be run by
-hand.
diff --git a/tools/build/v2/test/engine/action_status.jam b/tools/build/v2/test/engine/action_status.jam
deleted file mode 100644
index ee1c6c382a..0000000000
--- a/tools/build/v2/test/engine/action_status.jam
+++ /dev/null
@@ -1,28 +0,0 @@
-#~ 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)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing \"actions status results\"... ;
-
- assert "" 0 : (==) : [ SHELL "\"$(ARGV[1])\" -f action_status.jam -sBJAM_SUBTEST=1" : exit-status : no-output ] ;
- if $(NT)
- {
- assert "" 0 : (==) : [ SHELL "\"$(ARGV[1])\" -f action_status.jam -sBJAM_SUBTEST=1 \"-sACTION=;\"" : exit-status : no-output ] ;
- }
- assert "" 0 : (!=) : [ SHELL "\"$(ARGV[1])\" -f action_status.jam -sBJAM_SUBTEST=1 -sACTION=invalid" : exit-status : no-output ] ;
-}
-else
-{
- actions quietly .a. { $(ACTION) }
-
- rule .a.
- {
- DEPENDS $(<) : $(>) ;
- }
-
- NOTFILE subtest ;
- .a. subtest_a : subtest ;
- DEPENDS all : subtest_a ;
-}
diff --git a/tools/build/v2/test/engine/builtin_normalize_path.jam b/tools/build/v2/test/engine/builtin_normalize_path.jam
deleted file mode 100644
index 76e0a9ddb0..0000000000
--- a/tools/build/v2/test/engine/builtin_normalize_path.jam
+++ /dev/null
@@ -1,60 +0,0 @@
-#~ 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)
-
-ECHO --- Testing NORMALIZE_PATH builtin... ;
-
-assert "." : (==) : [ NORMALIZE_PATH ] ;
-assert "." : (==) : [ NORMALIZE_PATH "" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "." ] ;
-assert ".." : (==) : [ NORMALIZE_PATH ".." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "//" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\\\" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "//\\\\//\\\\" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/./" ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\\\///.///\\\\\\" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "./././././." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/./././././." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo/" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\\\/////" ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\\\/////././." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo\\\\/////./././" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo////.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "///foo/\\\\/.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "\\\\\\foo\\//\\.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/./.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/././././.." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo/./././bar/./././.././././baz/./././.." ] ;
-assert "/foo" : (==) : [ NORMALIZE_PATH "/foo/./././bar/./././.././././baz/./././.." ] ;
-assert "foo" : (==) : [ NORMALIZE_PATH "foo/./././bar/./././////.././././baz/./././.." ] ;
-assert "/foo" : (==) : [ NORMALIZE_PATH "/foo/./././bar/./././////.././././baz/./././.." ] ;
-assert ".." : (==) : [ NORMALIZE_PATH "./.." ] ;
-assert ".." : (==) : [ NORMALIZE_PATH "././././.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "../.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "./../.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "././././../.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "./.././././.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "././././.././././.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "..//\\\\\\//.." ] ;
-assert "../.." : (==) : [ NORMALIZE_PATH "../..\\\\/\\\\" ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo/../bar/../baz/.." ] ;
-assert "." : (==) : [ NORMALIZE_PATH "foo////..////bar////.//////.////../baz/.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/foo/../bar/../baz/.." ] ;
-assert "/" : (==) : [ NORMALIZE_PATH "/foo////..////bar////.//////.////../baz/.." ] ;
-
-# Invalid rooted paths with leading dotdots.
-assert : (==) : [ NORMALIZE_PATH "/.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../" ] ;
-assert : (==) : [ NORMALIZE_PATH "//\\\\//\\\\/.." ] ;
-assert : (==) : [ NORMALIZE_PATH "\\\\//\\\\//\\.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../../.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/foo/bar/../baz/../../.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../for/././../././bar/././../././.." ] ;
-assert : (==) : [ NORMALIZE_PATH "/../foo/bar" ] ;
diff --git a/tools/build/v2/test/engine/builtin_shell.jam b/tools/build/v2/test/engine/builtin_shell.jam
deleted file mode 100644
index 13d6245e32..0000000000
--- a/tools/build/v2/test/engine/builtin_shell.jam
+++ /dev/null
@@ -1,31 +0,0 @@
-#~ 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)
-
-# TODO: Here we should test for the Windows popen() command unquoting bug but
-# that test will have to wait until a better testing framework is implemented.
-# To reproduce the bug try executing any command with its first parameter quoted
-# and containing spaces and having at least one other quote in the command
-# string.
-#
-# 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
-
-ECHO --- Testing SHELL builtin... ;
-
-local c = "date" ;
-if $(NT) { c = "PATH" ; }
-
-assert "" : (!=) : [ SHELL $(c) ] ;
-assert "" : (==) : [ SHELL $(c) : no-output ] ;
-assert "" 0 : (!=) : [ SHELL $(c) : exit-status ] ;
-assert "" 0 : (==) : [ SHELL $(c) : no-output : exit-status ] ;
-assert "" : (!=) : [ COMMAND $(c) ] ;
-assert "" : (==) : [ COMMAND $(c) : no-output ] ;
-assert "" 0 : (!=) : [ COMMAND $(c) : exit-status ] ;
-assert "" 0 : (==) : [ COMMAND $(c) : no-output : exit-status ] ;
diff --git a/tools/build/v2/test/engine/builtin_w32_getregnames.jam b/tools/build/v2/test/engine/builtin_w32_getregnames.jam
deleted file mode 100644
index 1082f4ad72..0000000000
--- a/tools/build/v2/test/engine/builtin_w32_getregnames.jam
+++ /dev/null
@@ -1,17 +0,0 @@
-#~ 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)
-
-ECHO --- Testing W32_GETREGNAMES builtin... ;
-
-if $(NT)
-{
- assert "Beep" "ExtendedSounds"
- : (==) : [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : values ] ;
- assert "Beep" "ExtendedSounds"
- : (==) : [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ;
- assert "Control" "Enum" "Hardware Profiles" "Services"
- : (==) : [ W32_GETREGNAMES "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet" : subkeys ] ;
- assert "Control" "Enum" "Hardware Profiles" "Services"
- : (==) : [ W32_GETREGNAMES "HKLM\\SYSTEM\\CurrentControlSet" : subkeys ] ;
-}
diff --git a/tools/build/v2/test/engine/option_l.jam b/tools/build/v2/test/engine/option_l.jam
deleted file mode 100644
index 16299d631b..0000000000
--- a/tools/build/v2/test/engine/option_l.jam
+++ /dev/null
@@ -1,34 +0,0 @@
-#~ 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)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -l option... ;
-
- assert "...found 2 targets...
-...updating 1 target...
-.a. sleeper
-2 second time limit exceeded
-001
-
-echo 001
-sleep 4
-echo 002
-
-...failed .a. sleeper...
-...failed updating 1 target...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f option_l.jam -sBJAM_SUBTEST=1 -l2" ] ;
-}
-else
-{
- actions .a. {
-echo 001
-sleep 4
-echo 002
-}
-
- .a. sleeper ;
-
- DEPENDS all : sleeper ;
-}
diff --git a/tools/build/v2/test/engine/option_n.jam b/tools/build/v2/test/engine/option_n.jam
deleted file mode 100644
index 901dfed8db..0000000000
--- a/tools/build/v2/test/engine/option_n.jam
+++ /dev/null
@@ -1,44 +0,0 @@
-#~ 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)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -n option... ;
-
- assert "...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...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f option_n.jam -sBJAM_SUBTEST=1 -n" ] ;
-}
-else
-{
- 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 ;
-}
diff --git a/tools/build/v2/test/engine/parallel_multifile_actions_1.jam b/tools/build/v2/test/engine/parallel_multifile_actions_1.jam
deleted file mode 100644
index d11de7a123..0000000000
--- a/tools/build/v2/test/engine/parallel_multifile_actions_1.jam
+++ /dev/null
@@ -1,45 +0,0 @@
-#~ 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)
-
-if ! $(BJAM_SUBTEST)
-{
- ECHO --- Testing -jN parallel execution of multi-file actions - 1... ;
-
- assert "...found 6 targets...
-...updating 4 targets...
-.gen. g1.generated
-001
-002
-.use.1 u1.user
-003
-.use.2 u2.user
-004
-...updated 4 targets...
-" : (==) : [ SHELL "\"$(ARGV[1])\" -f parallel_multifile_actions_1.jam -sBJAM_SUBTEST=1 -j2" ] ;
-}
-else
-{
- actions .gen. {
-echo 001
-sleep 4
-echo 002
-}
- rule .use.1 { DEPENDS $(<) : $(>) ; }
- actions .use.1 {
-echo 003
-}
- 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 ;
-}
diff --git a/tools/build/v2/test/engine/rule_param.jam b/tools/build/v2/test/engine/rule_param.jam
deleted file mode 100644
index 8bc51becf3..0000000000
--- a/tools/build/v2/test/engine/rule_param.jam
+++ /dev/null
@@ -1,60 +0,0 @@
-#~ Copyright 2008 Jonathan Biggar
-#~ 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)
-
-ECHO -- Testing parameter passing... ;
-
-rule test_numeric_params
-{
- assert $(1) : (==) : 1 ;
- assert $(2) : (==) : 2 ;
- assert $(3) : (==) : 3 ;
- assert $(4) : (==) : 4 ;
- assert $(5) : (==) : 5 ;
- assert $(6) : (==) : 6 ;
- assert $(7) : (==) : 7 ;
- assert $(8) : (==) : 8 ;
- assert $(9) : (==) : 9 ;
- assert $(10) : (==) : 10 ;
- assert $(11) : (==) : 11 ;
- assert $(12) : (==) : 12 ;
- assert $(13) : (==) : 13 ;
- assert $(14) : (==) : 14 ;
- assert $(15) : (==) : 15 ;
- assert $(16) : (==) : 16 ;
- assert $(17) : (==) : 17 ;
- assert $(18) : (==) : 18 ;
- assert $(19) : (==) : 19 ;
-}
-
-rule test_named_params ( p1 : p2 : p3 : p4 : p5 : p6 : p7 : p8 : p9 :
- p10 : p11 : p12 : p13 : p14 : p15 : p16 : p17 : p18 : p19 )
-
-
-{
- assert $(p1) : (==) : 1 ;
- assert $(p2) : (==) : 2 ;
- assert $(p3) : (==) : 3 ;
- assert $(p4) : (==) : 4 ;
- assert $(p5) : (==) : 5 ;
- assert $(p6) : (==) : 6 ;
- assert $(p7) : (==) : 7 ;
- assert $(p8) : (==) : 8 ;
- assert $(p9) : (==) : 9 ;
- assert $(p10) : (==) : 10 ;
- assert $(p11) : (==) : 11 ;
- assert $(p12) : (==) : 12 ;
- assert $(p13) : (==) : 13 ;
- assert $(p14) : (==) : 14 ;
- assert $(p15) : (==) : 15 ;
- assert $(p16) : (==) : 16 ;
- assert $(p17) : (==) : 17 ;
- assert $(p18) : (==) : 18 ;
- assert $(p19) : (==) : 19 ;
-}
-
-test_numeric_params 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 :
- 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 ;
-
-test_named_params 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 :
- 10 : 11 : 12 : 13 : 14 : 15 : 16 : 17 : 18 : 19 ;
diff --git a/tools/build/v2/test/engine/stress_var_expand.jam b/tools/build/v2/test/engine/stress_var_expand.jam
deleted file mode 100644
index e76b36ab35..0000000000
--- a/tools/build/v2/test/engine/stress_var_expand.jam
+++ /dev/null
@@ -1,14 +0,0 @@
-#~ 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)
-
-ECHO --- Testing var expansion... ;
-
-local i = 0 ;
-local v = one two ;
-while $(i) != 4
-{
- i = [ CALC $(i) + 1 ] ;
- v = $(v)$(v) ;
- assert $(i) : (==) : $(i) ;
-}
diff --git a/tools/build/v2/test/engine/target_var.jam b/tools/build/v2/test/engine/target_var.jam
deleted file mode 100644
index d4fdae6314..0000000000
--- a/tools/build/v2/test/engine/target_var.jam
+++ /dev/null
@@ -1,16 +0,0 @@
-#~ 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)
-
-ECHO --- Testing var on target semantics... ;
-
-v on a = 1 ;
-v on b = 1 2 ;
-v on c = 1 2 3 ;
-v on d ?= 1 2 3 4 ;
-v on d ?= 5 6 7 8 ;
-v on a ?= 2 ;
-assert [ on a return $(v) ] : (==) : 1 ;
-assert [ on b return $(v) ] : (==) : 1 2 ;
-assert [ on c return $(v) ] : (==) : 1 2 3 ;
-assert [ on d return $(v) ] : (==) : 1 2 3 4 ;
diff --git a/tools/build/v2/test/engine/test.bat b/tools/build/v2/test/engine/test.bat
deleted file mode 100644
index a364fb50f3..0000000000
--- a/tools/build/v2/test/engine/test.bat
+++ /dev/null
@@ -1,53 +0,0 @@
-@ECHO OFF
-
-REM ~ Copyright 2006-2008 Rene Rivera.
-REM ~ Distributed under the Boost Software License, Version 1.0.
-REM ~ (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-
-REM ~ set BJAM=bjam
-REM ~ set BJAM_SRC=..\src
-REM ~ set BJAM_BIN=..\src\bin.ntx86\bjam.exe
-
-setlocal
-goto Start
-
-:Test_Path
-REM Tests for the given file(executable) presence in the directories in the PATH
-REM environment variable. Additionaly sets FOUND_PATH to the path of the
-REM found file.
-setlocal & endlocal & ver>NUL
-setlocal
-set test=%~$PATH:1
-endlocal
-if not errorlevel 1 set FOUND_PATH=%~dp$PATH:1
-goto :eof
-
-:Guess_BJAM
-setlocal & endlocal & ver>NUL
-if NOT "_%BJAM%_" == "__" goto :eof
-call :Test_Path bjam.exe
-if not errorlevel 1 (
- set BJAM=bjam.exe
- goto :eof)
-if "_%BJAM%_" == "__" (
- set BJAM=%BJAM_BIN%
- goto :eof)
-setlocal & endlocal & ver>NUL
-goto :eof
-
-:Build_BJAM_To_Test
-setlocal & endlocal & ver>NUL
-if "_%BJAM_SRC%_" == "__" set BJAM_SRC=..\src
-PUSHD %BJAM_SRC%
-call build.bat
-@ECHO OFF
-POPD
-set BJAM_BIN=%BJAM_SRC%\bin.ntx86\bjam.exe
-setlocal & endlocal & ver>NUL
-goto :eof
-
-:Start
-call :Build_BJAM_To_Test
-call :Guess_BJAM
-@ECHO ON
-%BJAM% -f test.jam "-sBJAM=%BJAM_BIN%"
diff --git a/tools/build/v2/test/engine/test.jam b/tools/build/v2/test/engine/test.jam
deleted file mode 100644
index f6f537766d..0000000000
--- a/tools/build/v2/test/engine/test.jam
+++ /dev/null
@@ -1,91 +0,0 @@
-#~ Copyright 2006-2008 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)
-
-TESTS =
- action_status
- actions_quietly
- builtin_normalize_path
- builtin_shell
- builtin_w32_getregnames
- option_d2
- option_l
- option_n
- parallel_actions
- parallel_multifile_actions_1
- parallel_multifile_actions_2
- rule_param
- stress_var_expand
- target_var
- var_expand
- ;
-
-BJAM ?= bjam ;
-
-#############################################################################
-
-if $(BJAM_RUN_TEST)
-{
- fail-count = 0 ;
- pass-count = 0 ;
-
- rule message ( message * )
- {
- local b = [ BACKTRACE ] ;
- ECHO "$(b[-4]):$(b[-3]):" $(message) ;
- }
-
-
- rule fail ( message * )
- {
- fail-count = [ CALC $(fail-count) + 1 ] ;
- message "error:" [FAILED] $(message) ;
- }
-
-
- rule pass ( message * )
- {
- pass-count = [ CALC $(pass-count) + 1 ] ;
- if --verbose in $(ARGV)
- {
- message "info:" [PASSED] $(message) ;
- }
- }
-
-
- rule assert ( expected * : test ? : obtained * )
- {
- test ?= "(==)" ;
- local r = 0 ;
- if $(test) = "(==)" && "*$(expected)*" != "*$(obtained)*"
- {
- fail '$(expected)' $(test) '$(obtained)' ;
- }
- else if $(test) = "(!=)" && "*$(expected)*" = "*$(obtained)*"
- {
- fail '$(expected)' $(test) '$(obtained)' ;
- }
- else
- {
- pass '$(expected)' $(test) '$(obtained)' ;
- }
- }
-
- include $(BJAM_RUN_TEST).jam ;
-
- EXIT --- $(BJAM_RUN_TEST): PASSED($(pass-count)) *FAILED($(fail-count))* : $(fail-count) ;
-}
-else
-{
- ECHO "Testing: $(BJAM)" ;
- fail-count = 0 ;
-
- for local test in $(TESTS)
- {
- local result = [ SHELL "\"$(BJAM)\" -f test.jam -sBJAM_RUN_TEST=$(test)" : exit-status ] ;
- fail-count = [ CALC $(fail-count) + $(result[1]) ] ;
- ECHO $(result[0]) ;
- }
-
- EXIT --- Complete: *FAILED($(fail-count))* : $(fail-count) ;
-}
diff --git a/tools/build/v2/test/engine/test.sh b/tools/build/v2/test/engine/test.sh
deleted file mode 100755
index 5c092836a7..0000000000
--- a/tools/build/v2/test/engine/test.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/bin/sh
-
-#~ Copyright 2006-2008 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)
-
-#~ BJAM=bjam
-#~ BJAM_SRC=../src
-#~ BJAM_BIN=`ls -1 ${BJAM_SRC}/bin.*/bjam`
-
-# Run a command, and echo before doing so. Also checks the exit
-# status and quits if there was an error.
-echo_run ()
-{
- echo "$@"
- $@
- r=$?
- if test $r -ne 0 ; then
- exit $r
- fi
-}
-
-# Check that a command is in the PATH.
-test_path ()
-{
- if `command -v command 1>/dev/null 2>/dev/null`; then
- command -v $1 1>/dev/null 2>/dev/null
- else
- hash $1 1>/dev/null 2>/dev/null
- fi
-}
-
-Guess_BJAM ()
-{
- if test_path bjam ; then BJAM=bjam
- elif test -r ./bjam ; then BJAM=./bjam
- elif test -r "${BJAM_BIN}" ; then BJAM="${BJAM_BIN}"
- fi
-}
-
-Build_BJAM_To_Test ()
-{
- cwd=`pwd`
- if test "${BJAM_SRC}" = "" ; then BJAM_SRC=../src ; fi
- cd "${BJAM_SRC}"
- ./build.sh
- if test "${BJAM_BIN}" = "" ; then BJAM_BIN=`ls -1 ${BJAM_SRC}/bin.*/bjam` ; fi
- cd "${cwd}"
-}
-
-Build_BJAM_To_Test
-Guess_BJAM
-echo_run "${BJAM}" -f test.jam "-sBJAM=${BJAM_BIN}" "$@"
diff --git a/tools/build/v2/test/engine/var_expand.jam b/tools/build/v2/test/engine/var_expand.jam
deleted file mode 100644
index 00b03a0ce1..0000000000
--- a/tools/build/v2/test/engine/var_expand.jam
+++ /dev/null
@@ -1,19 +0,0 @@
-#~ 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)
-
-ECHO --- Testing var expansion... ;
-
-local p0 = name ;
-local p1 = dir/name ;
-local p2 = dir/sub/name ;
-
-assert name : (==) : $(p0:D=) ;
-assert name : (==) : $(p1:D=) ;
-assert name : (==) : $(p2:D=) ;
-assert "" : (==) : $(p0:D) ;
-assert dir : (==) : $(p1:D) ;
-assert dir/sub : (==) : $(p2:D) ;
-assert "" : (==) : $(p0:S) ;
-assert ($(p0)) : (==) : [ MATCH ^@(.*) : "@($(p0))" ] ;
-assert ($(p0)) : (==) : [ MATCH @(.*) : "--@($(p0))" ] ;
diff --git a/tools/build/v2/test/file_name_handling.py b/tools/build/v2/test/file_name_handling.py
deleted file mode 100755
index 8e59e6821a..0000000000
--- a/tools/build/v2/test/file_name_handling.py
+++ /dev/null
@@ -1,255 +0,0 @@
-#!/usr/bin/python
-
-# 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)
-
-# Tests Boost Jam & Boost Build's source & target file name handling. Originally
-# added as a regression test for a bug causing versions included in the Boost
-# library 1.35 release (and earlier) not handling Windows short file names
-# correctly. Also tests handling target file names containing spaces.
-
-# Implementation notes:
-#
-# We expect Boost Jam to automatically update the 'all' target when no target
-# has been explicitly specified on the command line.
-#
-# Windows short & long file names can not be matched until the file in
-# question actually exists so we need to create the file before running Boost
-# Jam.
-#
-# Currently Windows short file names are hardcoded but in case this proves
-# insufficient we should use the GetShortPathName() Windows API to get the
-# correct short file for a given long file name.
-# (30.04.2008.) (Jurko)
-
-import BoostBuild
-import os
-import time
-
-
-################################################################################
-#
-# prepare_file()
-# --------------
-#
-################################################################################
-
-def prepare_file(tester, target_name, age_in_seconds=0):
- """Prepares a new file with the given name, optionally setting its last
- access and modification timestamps to the given number of seconds in the
- history.
- """
- tester.write( target_name, "Original file content." )
- if ( ( not age_in_seconds is None ) and ( age_in_seconds != 0 ) ):
- t = time.time() - age_in_seconds
- os.utime( tester.native_file_name( target_name ), ( t, t ) )
-
-
-################################################################################
-#
-# test_simple_file_names()
-# ------------------------
-#
-################################################################################
-
-def test_simple_file_names():
- """Runs simple file name handling that is not expected to fail anywhere. Not
- really needed for regular testing but the test is really fast and its
- content may be used for comparing to other more complex test functions in
- this module which test the same system but with some potentially more
- problematic file names.
- """
- t = BoostBuild.Tester(pass_toolset=0)
-
- prepare_file(t, "source.txt" )
- prepare_file(t, "target.txt" , 120)
- prepare_file(t, "target_noupdate.txt", 240)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo "Modified file content ($(1:E=""))."> "$(1:E="")"
-}
-
-DEPENDS all : standaloneTarget.txt ;
-create-file standaloneTarget.txt : all ;
-
-DEPENDS all : target.txt ;
-DEPENDS target.txt : source.txt ;
-create-file target.txt ;
-
-NOUPDATE target_noupdate.txt ;
-DEPENDS all : target_noupdate.txt ;
-DEPENDS target_noupdate.txt : source.txt ;
-create-file target_noupdate.txt ;
-
-create-file shouldNotBeCreated1 ;
-create-file shouldNotBeCreated2 ;
-create-file shouldNotBeCreated3 ;
-""")
-
- t.run_build_system("-ftestScript.jam")
- t.expect_addition("standaloneTarget.txt")
- t.expect_modification("target.txt")
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# test_short_file_name_with_action()
-# ----------------------------------
-#
-################################################################################
-
-def test_short_file_name_with_action():
- """Tests how Boost Jam handles the case when a Windows short file name is
- passed to a Boost Jam action.
- """
- if ( not BoostBuild.windows ):
- return
-
- t = BoostBuild.Tester(pass_toolset=0)
-
- long_file_name1 = "1__target that should be rebuilt.txt"
- long_file_name2 = "2__target that should be rebuilt.txt"
- short_file_name2 = "2__tar~1.txt"
-
- prepare_file(t, long_file_name1)
- prepare_file(t, long_file_name2)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo Modified file content ($(1:E="")).> "$(1:E="")"
-}
-
-ALWAYS "%(long_file_name1)s" ;
-DEPENDS all : "%(long_file_name1)s" ;
-create-file "%(long_file_name1)s" ;
-
-ALWAYS "%(long_file_name2)s" ;
-DEPENDS all : "%(long_file_name2)s" ;
-create-file "%(short_file_name2)s" ;
-""" % {'long_file_name1': long_file_name1,
- 'long_file_name2' : long_file_name2,
- 'short_file_name2' : short_file_name2})
-
- t.run_build_system("-ftestScript.jam")
- t.expect_modification(long_file_name1)
- t.expect_modification(long_file_name2)
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# test_short_file_name_with_ALWAYS()
-# ----------------------------------
-#
-################################################################################
-
-def test_short_file_name_with_ALWAYS():
- """Tests how Boost Jam handles the case when a Windows short file name is
- passed to the builtin ALWAYS rule.
- """
- if ( not BoostBuild.windows ):
- return
-
- t = BoostBuild.Tester(pass_toolset=0)
-
- long_file_name1 = "1__target that should be rebuilt.txt"
- long_file_name2 = "2__target that should be rebuilt.txt"
- short_file_name2 = "2__tar~1.txt"
-
- prepare_file(t, long_file_name1)
- prepare_file(t, long_file_name2)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo Modified file content ($(1:E="")).> "$(1:E="")"
-}
-
-ALWAYS "%(long_file_name1)s" ;
-DEPENDS all : "%(long_file_name1)s" ;
-create-file "%(long_file_name1)s" ;
-
-ALWAYS "%(short_file_name2)s" ;
-DEPENDS all : "%(long_file_name2)s" ;
-create-file "%(long_file_name2)s" ;
-""" % {'long_file_name1': long_file_name1,
- 'long_file_name2' : long_file_name2,
- 'short_file_name2' : short_file_name2})
-
- t.run_build_system("-ftestScript.jam")
- t.expect_modification(long_file_name1)
- t.expect_modification(long_file_name2)
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# test_short_file_name_with_NOUPDATE()
-# ------------------------------------
-#
-################################################################################
-
-def test_short_file_name_with_NOUPDATE():
- """Tests how Boost Jam handles the case when a Windows short file name is
- passed to the builtin NOUPDATE rule.
- """
- if ( not BoostBuild.windows ):
- return
-
- t = BoostBuild.Tester(pass_toolset=0)
-
- long_file_name1 = "1__target that should be rebuilt.txt"
- long_file_name2 = "2__target that should not be rebuilt.txt"
- short_file_name2 = "2__tar~1.txt"
-
- prepare_file(t, "source.txt" )
- prepare_file(t, long_file_name1, 120)
- prepare_file(t, long_file_name2, 120)
-
- t.write("testScript.jam", """
-actions create-file
-{
- echo Modified file content ($(1:E="")).> "$(1:E="")"
-}
-
-DEPENDS all : "%(long_file_name1)s" ;
-DEPENDS "%(long_file_name1)s" : source.txt ;
-create-file "%(long_file_name1)s" ;
-
-NOUPDATE "%(short_file_name2)s" ;
-DEPENDS all : "%(long_file_name2)s" ;
-DEPENDS "%(long_file_name2)s" : source.txt ;
-create-file "%(long_file_name2)s" ;
-""" % {'long_file_name1': long_file_name1,
- 'long_file_name2' : long_file_name2,
- 'short_file_name2' : short_file_name2})
-
- t.run_build_system("-ftestScript.jam")
- t.expect_modification(long_file_name1)
- t.expect_nothing_more()
-
- t.cleanup()
-
-
-################################################################################
-#
-# main()
-# ------
-#
-################################################################################
-
-test_simple_file_names()
-test_short_file_name_with_action()
-test_short_file_name_with_ALWAYS()
-test_short_file_name_with_NOUPDATE()
diff --git a/tools/build/v2/test/jamfile.jam b/tools/build/v2/test/jamfile.jam
deleted file mode 100644
index 9d186f3c1f..0000000000
--- a/tools/build/v2/test/jamfile.jam
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2001 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)
-
-
-# establish a project root right here in the test directory, so that we can test
-# things independently of the boost jambase, etc.
-project-root ;
-
-include check-test-tools.jam ;
-include check-jam-patches.jam ;
diff --git a/tools/build/v2/test/load_order.py b/tools/build/v2/test/load_order.py
index 34ceaaf448..183bf2440b 100644
--- a/tools/build/v2/test/load_order.py
+++ b/tools/build/v2/test/load_order.py
@@ -61,4 +61,28 @@ int main() {}
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", """
+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.run_build_system(subdir="child/child1")
+t.expect_output_line("Running parent-rule")
+
t.cleanup()
diff --git a/tools/build/v2/test/m1-01.py b/tools/build/v2/test/m1-01.py
deleted file mode 100644
index 6c42c1eec8..0000000000
--- a/tools/build/v2/test/m1-01.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/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)
-
-# Test the very basic 'make' functionality.
-
-import BoostBuild
-
-t = BoostBuild.Tester()
-
-t.set_tree("test1")
-
-# Check that we can build something.
-t.run_build_system("-sTOOLSET=yfc")
-
-t.expect_addition("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_addition("bin/a/yfc/debug/runtime-link-dynamic/a")
-t.expect_nothing_more()
-
-t.fail(t.read("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("bin/a/yfc/debug/runtime-link-dynamic/a") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-# Check that we have vanilla target names available.
-t.touch("a.cpp")
-t.run_build_system("-sTOOLSET a.obj")
-t.expect_touch("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_no_modification("bin/a/yfc/debug/runtime-link-dynamic/a")
-
-
-# Check that if a build request cannot be completely matches, a warning is
-# issued and a subvariant with link-compatible properties is used.
-t.write("jamfile.jam", t.read("jamfile2.jam"))
-stdout="""Warning: cannot exactly satisfy request for ./a with properties
- <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Using
- <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-instead.
-""")
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-# Check that conflicting link-incompatible requirements prevent building.
-t.write("jamfile.jam", t.read("jamfile3.jam"))
-stdout="""Warning: cannot satisfy request for ./a with properties
- <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Nothing will be built.
-""")
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout, status=1)
-
-t.pass_test()
diff --git a/tools/build/v2/test/m1-02.py b/tools/build/v2/test/m1-02.py
deleted file mode 100644
index 13cc9dc1ae..0000000000
--- a/tools/build/v2/test/m1-02.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/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)
-
-# Tests that 'make' accepts targets from other directories and that build
-# requests for those targets can be overriden.
-
-import BoostBuild
-
-t = BoostBuild.Tester()
-
-t.set_tree("test1")
-
-t.run_build_system("-sTOOLSET=yfc")
-
-t.expect_addition("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_addition("auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/optimization-space/b.obj")
-t.expect_addition("bin/a/yfc/debug/runtime-link-dynamic/a")
-t.expect_nothing_more()
-
-t.fail(t.read("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/b.obj") !=\
-"""
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-""")
-
-t.fail(t.read("bin/a/yfc/debug/runtime-link-dynamic/a") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-""")
-
-# Check that we have vanilla target names available in subdirs.
-t.touch("auxillary/b.cpp")
-t.run_build_system("-sTOOLSET b.obj", subdir="auxillary")
-t.expect_touch("auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/optimization-space/b.obj")
-t.expect_no_modification("bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_no_modification("bin/a/yfc/debug/runtime-link-dynamic/a")
-
-
-# Check that we can not request link-incompatible property for source target.
-t.write('jamfile.jam', t.read('jamfile2.jam'))
-stdout="""Error: subvariant of target ./a with properties
- <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-requests link-incompatible property
- <rtti>off
-for source @auxillary/b.obj
-"""
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-
-# Check that if we request link-compatible property then requirement for the
-# source target will override it, with a warning. This is similar to the way
-# build requests are satisfied (see the first test).
-#
-# CONSIDER: should be print the main target which requests this one (and
-# modifies requirements)?
-t.write('jamfile.jam', t.read('jamfile3.jam'))
-t.write('auxillary/jamfile.jam', t.read('auxillary/jamfile3.jam'))
-stdout="""Warning: cannot exactly satisfy request for auxillary/b.obj with properties
- <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Using
- <optimization>speed <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-instead.
-"""
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-
-# Check for link-incompatible properties.
-t.write('jamfile.jam', t.read('jamfile4.jam'))
-t.write('auxillary/jamfile.jam', t.read('auxillary/jamfile4.jam'))
-stdout="""Warning: cannot satisfy request for auxillary/b.obj with properties
- <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-Nothing will be built.
-"""
-t.run_build_system("-sTOOLSET=yfc", stdout=stdout)
-
-
-t.pass_test()
diff --git a/tools/build/v2/test/m1-03.py b/tools/build/v2/test/m1-03.py
deleted file mode 100644
index 2f31ba27c8..0000000000
--- a/tools/build/v2/test/m1-03.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/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)
-
-# Tests that we can use objects from other projects, i.e. with other project
-# root. Test also that we can refer to those target using project-id.
-
-import BoostBuild
-
-t = BoostBuild.Tester()
-
-t.set_tree("test1")
-
-t.run_build_system("-sTOOLSET=yfc", subdir="p1")
-
-t.expect_addition("p1/bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj")
-t.expect_addition("p1/auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/optimization-space/b.obj")
-t.expect_addition("p2/bin/c.obj/yfc/debug/runtime-link-dynamic/c.obj")
-t.expect_addition("bin/a/yfc/debug/runtime-link-dynamic/a")
-t.expect_nothing_more()
-
-t.fail(t.read("p1/bin/a.obj/yfc/debug/runtime-link-dynamic/a.obj") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("p1/auxillary/bin/b.obj/yfc/debug/runtime-link-dynamic/b.obj") !=\
-"""
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-""")
-
-t.fail(t.read("p2/bin/c.obj/yfc/debug/runtime-link-dynamic/c.obj") !=\
-"""
-<include>everything <optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-""")
-
-t.fail(t.read("bin/a/yfc/debug/runtime-link-dynamic/a") !=\
-"""
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-<optimization>off <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-a.cpp
-<optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-b.cpp
-<include>everything <optimization>space <rtti>on <runtime-link>dynamic <toolset>yfc <variant>debug
-c.cpp
-""")
-
-t.expect_nothing_more()
-
-# TODO: need to write test cases for referring to targets using project-id.
-
-t.pass_test()
diff --git a/tools/build/v2/test/prebuilt/ext/jamfile2.jam b/tools/build/v2/test/prebuilt/ext/jamfile2.jam
index dd79f4ea2d..cd59663d6d 100644
--- a/tools/build/v2/test/prebuilt/ext/jamfile2.jam
+++ b/tools/build/v2/test/prebuilt/ext/jamfile2.jam
@@ -1,9 +1,9 @@
-import modules ;
+import os ;
local dll-suffix = so ;
local prefix = "" ;
-if [ modules.peek : OS ] in CYGWIN NT
+if [ os.name ] in CYGWIN NT
{
if [ MATCH ^(gcc) : $toolset ]
{
diff --git a/tools/build/v2/test/prebuilt/ext/jamfile3.jam b/tools/build/v2/test/prebuilt/ext/jamfile3.jam
index f172a89d08..a373a5fb21 100644
--- a/tools/build/v2/test/prebuilt/ext/jamfile3.jam
+++ b/tools/build/v2/test/prebuilt/ext/jamfile3.jam
@@ -3,11 +3,11 @@
# it tries to access prebuilt targets using absolute
# paths. It used to be broken on Windows.
-import modules ;
+import os ;
local dll-suffix = so ;
local prefix = "" ;
-if [ modules.peek : OS ] in CYGWIN NT
+if [ os.name ] in CYGWIN NT
{
if [ MATCH ^(gcc) : $toolset ]
{
diff --git a/tools/build/v2/test/project-test1.jam b/tools/build/v2/test/project-test1.jam
deleted file mode 100644
index c2d6ae5763..0000000000
--- a/tools/build/v2/test/project-test1.jam
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2002, 2003 Dave Abrahams
-# Copyright 2002 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)
-
-import project ;
-import targets ;
-import assert ;
-
-project.load project-test1 ;
-import project-roots ;
-
-project-roots.print ;
-
-NOTFILE all ;
-
-
diff --git a/tools/build/v2/test/project-test1/dir/jamfile.jam b/tools/build/v2/test/project-test1/dir/jamfile.jam
deleted file mode 100644
index 3434eb7911..0000000000
--- a/tools/build/v2/test/project-test1/dir/jamfile.jam
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2003 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)
-
-
-project /boost-build-test-project-1/dir
- : source-location src
- : default-build release
- ;
diff --git a/tools/build/v2/test/project-test1/dir2/jamroot.jam b/tools/build/v2/test/project-test1/dir2/jamroot.jam
deleted file mode 100644
index 8cfc3a28e9..0000000000
--- a/tools/build/v2/test/project-test1/dir2/jamroot.jam
+++ /dev/null
@@ -1,4 +0,0 @@
-# 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)
-
diff --git a/tools/build/v2/test/project-test1/jamfile.jam b/tools/build/v2/test/project-test1/jamfile.jam
deleted file mode 100644
index d343ba6df6..0000000000
--- a/tools/build/v2/test/project-test1/jamfile.jam
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 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)
-
-project /boost-build-test-project-1
- : requirements <threading>multi <include>/home/ghost/local/include ;
-
-build-project dir2 ;
-build-project dir ;
diff --git a/tools/build/v2/test/project-test1/jamroot.jam b/tools/build/v2/test/project-test1/jamroot.jam
deleted file mode 100644
index a61a11c1d5..0000000000
--- a/tools/build/v2/test/project-test1/jamroot.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# 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)
-
-
-import builtin ;
diff --git a/tools/build/v2/test/project-test1/project-test1.jam b/tools/build/v2/test/project-test1/project-test1.jam
deleted file mode 100644
index 2f2aad25c8..0000000000
--- a/tools/build/v2/test/project-test1/project-test1.jam
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2002, 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)
-
-import project ;
-import targets ;
-import assert ;
-import project-roots ;
-
-project.load "." ;
-
-import standalone-project ;
-
-project-roots.print ;
-
-assert.result standalone-project : project.find /teeest : "." ;
-
-NOTFILE all ;
-
-
diff --git a/tools/build/v2/test/project-test1/readme.txt b/tools/build/v2/test/project-test1/readme.txt
deleted file mode 100644
index 0001799243..0000000000
--- a/tools/build/v2/test/project-test1/readme.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Copyright 2003 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)
-
-
-This tests for basic project handling -- declaring subprojects, finding
-parent projects and project roots and for working project-ids.
diff --git a/tools/build/v2/test/project-test1/standalone-project.jam b/tools/build/v2/test/project-test1/standalone-project.jam
deleted file mode 100644
index 48249b561d..0000000000
--- a/tools/build/v2/test/project-test1/standalone-project.jam
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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)
-
-
-import project ;
-
-# Convert ourself into a real project.
-project.initialize $(__name__) ;
-
-# Now we can identify ourselfs.
-project /teeest ;
diff --git a/tools/build/v2/test/project_test1.py b/tools/build/v2/test/project_test1.py
deleted file mode 100644
index a2a2ada186..0000000000
--- a/tools/build/v2/test/project_test1.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 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)
-
-import BoostBuild
-import os
-
-t = BoostBuild.Tester("--build-system=project-test1", boost_build_path='',
- pass_toolset=0)
-
-# This test does no modifications, so run in in the invocation dir.
-os.chdir(t.original_workdir)
-
-expected_output1="""Project Roots:
-
-"""
-
-expected_output2="""'%(root-dir-prefix)sdir2':
-
- Module for project-root is 'project-root<%(root-dir-prefix)sdir2>'
-
-Projects:
-
-'/cool-library':
-
-* Parent project: (none)
-* Requirements: <include>/home/ghost/build/boost-cvs
-* Default build:
-* Source location: %(root-dir-prefix)sdir2
-* Projects to build:
-
-"""
-
-expected_output3="""'%(root-dir)s':
-
- Module for project-root is 'project-root<%(root-dir)s>'
-
-Projects:
-
-'/boost-build-test-project-1':
-
-* Parent project: (none)
-* Requirements: <include>/home/ghost/local/include <threading>multi
-* Default build:
-* Source location: %(root-dir)s
-* Projects to build: dir dir2
-
-'/boost-build-test-project-1/dir':
-
-* Parent project: %(root-dir)s
-* Requirements: <include>/home/ghost/local/include <threading>multi
-* Default build: <variant>release
-* Source location: %(root-dir-prefix)sdir/src
-* Projects to build:
-
-"""
-
-# Test that correct project structure is created when jam is invoked outside of
-# the source tree.
-expected = (expected_output1 + expected_output2 + expected_output3) % \
- {"root-dir": "project-test1",
- "root-dir-prefix": "project-test1/" }
-
-t.run_build_system(stdout=expected)
-
-# Test that correct project structure is created when jam is invoked at the top
-# of the source tree.
-expected = (expected_output1 + expected_output3 + expected_output2) % \
- {"root-dir": ".",
- "root-dir-prefix": "" }
-
-os.chdir("project-test1")
-t.run_build_system(stdout=expected)
-
-t.cleanup()
diff --git a/tools/build/v2/test/recursive.jam b/tools/build/v2/test/recursive.jam
deleted file mode 100644
index 8087f7da75..0000000000
--- a/tools/build/v2/test/recursive.jam
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright 2001, 2002 Dave 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)
-
-##############################################################
-# Rules and actions that test Jam by invoking it recursively #
-# #
-# This is necessary for testing anything that requires Jam #
-# to execute build actions whose results must be checked, #
-# and anything which exits Jam with a failure code (e.g. a #
-# failed assertion). #
-##############################################################
-
-# Creates a fake target, always built, which succeeds in building if Invoking a
-# Jamfile containing the given string succeeds. If optional-expected-output is
-# supplied, creates another fake target which succeeds in building if
-# optional-expected-output is in the Jam output.
-#
-# RETURNS: the target name of the Jam command.
-rule Jam ( command : expected-output ? )
-{
- local jam-cmd = "$(command:G=jam_command)" ;
-
- NOTFILE "$(jam-cmd)" ;
- ALWAYS "$(jam-cmd)" ;
- DEPENDS all : "$(jam-cmd)" ;
-
- if ($NT)
- {
- redirect on $(jam-cmd) = "nul" ;
- }
- else if $(UNIX)
- {
- redirect on $(jam-cmd) = "/dev/null" ;
- }
-
- if $(VERBOSE)
- {
- redirect on $(jam-cmd) = ;
- }
-
- invoke-Jam "$(jam-cmd)" ;
-
- if $(expected-output)
- {
- redirect on $(jam-cmd) = "scratch-output.txt" ;
- local output-target = "$(expected-output:G=$(command))" ;
- NOTFILE "$(output-target)" ;
- ALWAYS "$(output-target)" ;
- DEPENDS all : "$(output-target)" ;
- Expect-in-output "$(output-target)" ;
-
- if $(VERBOSE)
- {
- if $(NT) { VERBOSE on $(output-target) = "type " ; }
- else { VERBOSE on $(output-target) = "cat " ; }
- }
- }
- return $(jam-cmd) ;
-}
-
-# Just like the "Jam" rule, above, but only succeeds if the Jam command /fails/.
-rule Jam-fail ( command : expected-output ? )
-{
- local target = [ Jam $(command) : $(expected-output) ] ;
- FAIL_EXPECTED $(target) ;
- return $(target) ;
-}
-
-# The temporary jamfile we write is called "temp.jam". If the user has set
-# BOOST_BUILD_ROOT, it will be built there.
-gBOOST_TEST_JAMFILE = temp.jam ;
-LOCATE on gBOOST_TEST_JAMFILE ?= $(BOOST_BUILD_ROOT) ;
-
-# Runs Jam on a temporary Jamfile which contains the string in $(command:G=)
-# and redirects the results into a file whose name is given by $(redirect) on
-# command
-rule invoke-Jam ( command )
-{
- PREFIX on $(command) = "actions unbuilt { } unbuilt all ;" ;
- if $(NT)
- {
- REMOVE on $(command) = $(SystemRoot)\System32\find ;
- }
- REMOVE on $(command) ?= rm ;
-}
-actions invoke-Jam
-{
- echo $(PREFIX) $(<:G=) > $(gBOOST_TEST_JAMFILE)
- jam -sBOOST_ROOT=../../.. -sJAMFILE=$(gBOOST_TEST_JAMFILE) $(JAMARGS) >$(redirect)
-}
-# $(REMOVE) $(gBOOST_TEST_JAMFILE)
-
-
-# These actions expect to find the ungristed part of $(<) in scratch-output.txt
-# and return a nonzero exit code otherwise
-if $(NT)
-{
- # Explicitly get the NT find command in case someone has another find in their path.
- actions quietly Expect-in-output
- {
- $(VERBOSE)scratch-output.txt ;
- $(SystemRoot)\System32\find /C "$(<:G=)" scratch-output.txt >nul
- }
-}
-else
-{
- # Not really the right actions for Unix; the argument will be interpreted as
- # a regular expression. Is there a simpler find?
- actions quietly Expect-in-output
- {
- $(VERBOSE)scratch-output.txt;
- grep "$(<:G=)" scratch-output.txt
- }
-}
-
diff --git a/tools/build/v2/test/startup_v1.py b/tools/build/v2/test/startup_v1.py
deleted file mode 100644
index 14a286a70f..0000000000
--- a/tools/build/v2/test/startup_v1.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 Dave Abrahams
-# 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)
-
-import BoostBuild
-import os
-import re
-
-def expect_substring(actual, expected):
- return actual.find(expected) != -1
-
-def match_re(actual, expected):
- return re.match(expected, actual, re.DOTALL) != None
-
-# Test the v1 startup behavior.
-t = BoostBuild.Tester(executable='bjam', match=match_re, boost_build_path='',
- pass_toolset=0)
-
-t.set_tree('startup')
-
-#if os.name == 'nt':
-# t.run_build_system(
-# status=1, stdout="You didn't set BOOST_ROOT", match = expect_substring)
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', status=1,
- stdout=r'''Unable to load Boost\.Build: could not find ''' +
- r'''"boost-build\.jam".''')
-
-os.chdir('no-bootstrap1')
-
-t.run_build_system(extra_args='-sBOOST_ROOT=.', 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(extra_args='-sBOOST_ROOT=.', 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(extra_args='-sBOOST_ROOT=.', 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(extra_args='-sBOOST_ROOT=.', status=1,
- 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_ROOT=../boost-root ' +
- '-sBOOST_BUILD_PATH=../boost-root/build',
- stdout='build system bootstrapped')
-
-# test bootstrapping based on an explicit path in boost-build.jam
-os.chdir('../bootstrap-explicit')
-t.run_build_system(extra_args='-sBOOST_ROOT=../boost-root',
- stdout='build system bootstrapped')
-
-# test bootstrapping based on BOOST_ROOT
-os.chdir('../bootstrap-implicit')
-t.run_build_system(extra_args='-sBOOST_ROOT=../boost-root',
- stdout='build system bootstrapped')
-
-t.cleanup()
diff --git a/tools/build/v2/test/subdir1/file-to-bind b/tools/build/v2/test/subdir1/file-to-bind
deleted file mode 100644
index 7ff128fa69..0000000000
--- a/tools/build/v2/test/subdir1/file-to-bind
+++ /dev/null
@@ -1 +0,0 @@
-# This file intentionally left blank \ No newline at end of file
diff --git a/tools/build/v2/test/test.jam b/tools/build/v2/test/test.jam
index 5e1aae9bcd..1ae1a2059e 100644
--- a/tools/build/v2/test/test.jam
+++ b/tools/build/v2/test/test.jam
@@ -4,20 +4,36 @@
# 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)
+# util
+import assert ;
+import container ;
import indirect ;
-import string ;
import numbers ;
-import sequence ;
-import "class" ;
+import order ;
import os ;
import path ;
+import print ;
+import regex ;
+import sequence ;
+import set ;
+import string ;
+import utility ;
+
+# kernel
+import "class" ;
+import errors ;
+import modules ;
+
+# build
+import build-request ;
import feature ;
import property ;
-import build-request ;
-import container ;
-import print ;
-import common ;
+import toolset ;
+import type ;
+import version ;
+# tools
+import common ;
actions nothing { }
nothing all ;
diff --git a/tools/build/v2/test/test1.py b/tools/build/v2/test/test1.py
index 3cdc71d2d2..05b3966483 100644
--- a/tools/build/v2/test/test1.py
+++ b/tools/build/v2/test/test1.py
@@ -6,7 +6,7 @@
import BoostBuild
-t = BoostBuild.Tester()
+t = BoostBuild.Tester(pass_toolset=0)
t.write("test.jam", """
actions unbuilt { }
@@ -15,4 +15,4 @@ ECHO "Hi" ;
""")
t.run_build_system("-ftest.jam", stdout="Hi\n")
-t.pass_test()
+t.cleanup()
diff --git a/tools/build/v2/test/test2.py b/tools/build/v2/test/test2.py
index b5c9ba824e..938b36545a 100644
--- a/tools/build/v2/test/test2.py
+++ b/tools/build/v2/test/test2.py
@@ -11,7 +11,7 @@ t = BoostBuild.Tester()
t.set_tree("test2")
-file_list = 'bin/foo/$toolset/debug/runtime-link-dynamic/' * \
+file_list = 'bin/$toolset/debug/' * \
BoostBuild.List("foo foo.o")
t.run_build_system("-sBOOST_BUILD_PATH=" + t.original_workdir + "/..")
@@ -22,4 +22,4 @@ t.write("foo.cpp", "int main() {}\n")
t.run_build_system("-d2 -sBOOST_BUILD_PATH=" + t.original_workdir + "/..")
t.expect_touch(file_list)
-t.pass_test()
+t.cleanup()
diff --git a/tools/build/v2/test/test2/Jamrules b/tools/build/v2/test/test2/Jamrules
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tools/build/v2/test/test2/Jamrules
+++ /dev/null
diff --git a/tools/build/v2/test/test2/jamfile.jam b/tools/build/v2/test/test2/jamroot.jam
index 670583964e..4fb3f28865 100644
--- a/tools/build/v2/test/test2/jamfile.jam
+++ b/tools/build/v2/test/test2/jamroot.jam
@@ -2,7 +2,4 @@
# 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)
-
-project-root ;
-
exe foo : foo.cpp ;
diff --git a/tools/build/v2/test/test_all.py b/tools/build/v2/test/test_all.py
index 59476bd740..b6aad705d9 100644
--- a/tools/build/v2/test/test_all.py
+++ b/tools/build/v2/test/test_all.py
@@ -118,10 +118,10 @@ def reorder_tests(tests, first_test):
return tests
-critical_tests = ["unit_tests", "module_actions", "startup_v1", "startup_v2"]
+critical_tests = ["unit_tests", "module_actions", "startup_v2"]
critical_tests += ["core_d12", "core_typecheck", "core_delete_module",
- "core_varnames", "core_import_module"]
+ "core_language", "core_arguments", "core_varnames", "core_import_module"]
tests = [ "absolute_sources",
"alias",
@@ -130,6 +130,8 @@ tests = [ "absolute_sources",
"build_dir",
"build_file",
"build_no",
+ "builtin_echo",
+ "builtin_exit",
"c_file",
"chain",
"clean",
@@ -140,6 +142,18 @@ tests = [ "absolute_sources",
"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",
@@ -147,6 +161,7 @@ tests = [ "absolute_sources",
# "default_toolset",
"dependency_property",
"dependency_test",
+ "direct_request_test",
"disambiguation",
"dll_path",
"double_loading",
@@ -155,7 +170,6 @@ tests = [ "absolute_sources",
"example_make",
"expansion",
"explicit",
- "file_name_handling",
"free_features_request",
"generator_selection",
"generators_test",
@@ -202,6 +216,7 @@ tests = [ "absolute_sources",
"testing_support",
"timedata",
"unit_test",
+ "unused",
"use_requirements",
"using",
"wrapper",
diff --git a/tools/build/v2/test/testing-primitives/boost-build.jam b/tools/build/v2/test/testing-primitives/boost-build.jam
deleted file mode 100644
index 667355a164..0000000000
--- a/tools/build/v2/test/testing-primitives/boost-build.jam
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2002 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)
-
-boost-build . ;
diff --git a/tools/build/v2/test/testing-primitives/bootstrap.jam b/tools/build/v2/test/testing-primitives/bootstrap.jam
deleted file mode 100644
index 2b1ad48542..0000000000
--- a/tools/build/v2/test/testing-primitives/bootstrap.jam
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright 2002 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)
-
-# Proof-of-concept for bjam-based testing mechanism. This file should
-# work on NT, Cygwin, and Linux. No promises for other platforms.
-
-# Set a variable which says how to dump a file to stdout
-if $(NT)
-{
- CATENATE = type ;
-}
-else
-{
- CATENATE = cat ;
-}
-
-# invoke the given action rule `act' to build target from sources
-rule do-make ( target : sources * : act )
-{
- DEPENDS $(target) : $(sources) ;
- $(act) $(target) : $(sources) ;
-}
-
-# top-level version of do-make which causes target to be built by
-# default
-rule make ( target : sources * : act )
-{
- DEPENDS all : $(target) ;
- do-make $(target) : $(sources) : $(act) ;
-}
-
-# cause `target' to exist and building to succeed if invoking
-#
-# $(act) $(target) : $(sources)
-#
-# fails, and to fail if the action succeeds.
-rule make-fail ( target : sources * : act )
-{
- # Establish another logical target which refers to the same file,
- # by using different grist.
- DEPENDS all : <different-grist>$(target) ;
-
- # Make the new logical target depend on the target
- DEPENDS <different-grist>$(target) : $(target) ;
-
- # Cause the target to be built from sources using $(act).
- do-make $(target) : $(sources) : $(act) ;
-
- # Note that we expect target to fail to build
- FAIL_EXPECTED $(target) ;
-
- # Build a failure marker file. Because targets are only built if
- # all their dependents "succeed", the marker will only be
- # generated if $(target) failed to build, as expected.
- failure-marker <different-grist>$(target) ;
-}
-
-# Simple action rules which write text into the target. Different
-# names for different purposes.
-actions failure-marker
-{
- echo failed as expected > $(<)
-}
-
-actions create
-{
- echo creating > $(<)
-}
-
-# An action which will always fail, for testing expected failure rules
-actions fail-to-create
-{
- exit 1
-}
-
-# Basic rule-action pair which builds the target by executing the
-# given commands
-rule do-run ( target : commands + )
-{
- COMMANDS on $(target) = $(commands) ;
- NOTFILE $(commands) ;
-}
-
-# Run commands, leaving the output behind in $(<:S=.out). Echo to
-# stdout if the command fails.
-#
-# Detailed explanation:
-#
-# $(COMMANDS) Run commands
-# > $(<:S=.out) into the output file
-# 2>&1 including stderr
-# && and if that succeeds
-# cp -f $(<:S=.out) $(<) copy the output file into the target
-# || otherwise
-# ( $(CATENATE) $(<:S=.out) dump any output to stdout
-# && exit 1 and exit with an error code
-# )
-actions do-run
-{
- $(COMMANDS) > $(<:S=.out) 2>&1 && cp -f $(<:S=.out) $(<) || ( $(CATENATE) $(<:S=.out) && exit 1 )
-}
-
-# top-level version of do-run which causes target to be built by
-# default
-rule run ( target : commands + )
-{
- DEPENDS all : $(target) ;
- do-run $(target) : $(commands) ;
-}
-
-# experimental expected-failure version of run. This doesn't have
-# quite the right semantics w.r.t. output dumping (it is still only
-# dumped if the run fails), but we don't need run-fail anyway so it
-# doesn't matter too much.
-rule run-fail ( target : commands + )
-{
- make-fail $(target) : $(commands) : do-run ;
-}
-
-# A command which will always fail to run. There is no file called
-# nonexistent, so executing $(error) always causes an error. We can't
-# just use `exit 1' below because that will cause all command
-# processing to stop, and we want the rest of the do-run action
-# command-line to execute.
-error = $(CATENATE)" nonexistent" ;
-
-make-fail t1.txt : : create ;
-make-fail t2.txt : : fail-to-create ;
-make t3.txt : : create ;
-make t4.txt : : fail-to-create ;
-
-run t5.txt : "( echo failing t5 && $(error) )" ;
-run t6.txt : echo hi ;
-
-run-fail t7.txt : "( echo failing t7 && $(error) )" ;
-run-fail t8.txt : echo hi ;
diff --git a/tools/build/v2/test/testing_primitives.py b/tools/build/v2/test/testing_primitives.py
deleted file mode 100644
index ae62993b32..0000000000
--- a/tools/build/v2/test/testing_primitives.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 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)
-
-import BoostBuild
-import re
-
-def match_re(actual, expected):
- return re.match(expected, actual, re.DOTALL) != None
-
-t = BoostBuild.Tester(match=match_re)
-
-t.set_tree('testing-primitives')
-
-# We expect t5 and t7's output to be dumped to stdout.
-t.run_build_system(stdout=r'''.*failing t5.*failing t7''')
-
-t.expect_addition('t2.txt')
-t.expect_addition('t3.txt')
-t.expect_addition('t5.out')
-t.expect_addition('t6.out')
-t.expect_addition('t6.txt')
-t.expect_addition('t7.out')
-t.expect_addition('t7.txt')
-t.expect_addition('t8.out')
-t.expect_nothing_more()
-
-t.cleanup()
diff --git a/tools/build/v2/test/unit-tests.jam b/tools/build/v2/test/unit-tests.jam
deleted file mode 100644
index 212f4c3887..0000000000
--- a/tools/build/v2/test/unit-tests.jam
+++ /dev/null
@@ -1,262 +0,0 @@
-# Copyright 2001 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)
-
-# assert_equal a : b
-#
-# exits with an assertion failure if a != b
-rule assert_equal
-{
- if $(<) != $(>)
- {
- EXIT "assertion failure: [" $(<) "] != [" $(>) "]" ;
- }
-}
-
-rule assert_equal_sets
-{
- if ! [ equal-sets $(<) : $(>) ]
- {
- EXIT "assertion failure: [" $(<) "] !=(set) [" $(>) "]" ;
- }
-}
-
-# FAppendSuffix
-assert_equal [ FAppendSuffix yacc lex foo.bat : ] : yacc lex foo.bat ;
-assert_equal [ FAppendSuffix yacc lex foo.bat : .exe ] : yacc.exe lex.exe foo.bat ;
-assert_equal [ FAppendSuffix yacc lex foo.bat : .dll .lib ] : yacc.dll yacc.lib lex.dll lex.lib foo.bat foo.lib ;
-
-# sort
-assert_equal [ sort 7 3 5 6 2 4 ] : 2 3 4 5 6 7 ;
-
-# min
-assert_equal [ min 7 3 5 6 2 4 ] : 2 ;
-
-# difference
-assert_equal [ difference 0 1 2 3 4 5 6 7 8 9 : 2 3 5 7 ] : 0 1 4 6 8 9 ;
-
-# replace
-assert_equal [ replace 1 3 5 7 7 9 2 5 4 3 1 : 7 x ] : 1 3 5 x x 9 2 5 4 3 1 ;
-
-# select-ungristed
-assert_equal [ select-ungristed <a>b c <d>e f ] : c f ;
-
-# split-qualified-property
-assert_equal [ split-qualified-property <feature>value ]
- : <*> <*> <feature>value ;
-
-assert_equal [ split-qualified-property <variant><feature>value ]
- : <*> <variant> <feature>value ;
-
-assert_equal [ split-qualified-property <toolset><variant><feature>value ]
- : <toolset> <variant> <feature>value ;
-
-# unique
-assert_equal [ unique 0 1 2 3 1 7 6 6 4 5 ] : 0 1 2 3 7 6 4 5 ;
-
-# get-properties
-assert_equal [ get-properties <foo> <bar> : <foo>bar <foo>baz <bar>fight <baz>niss ]
- : <foo>bar <foo>baz <bar>fight ;
-
-# get-values
-assert_equal [ get-values <foo> : <foo>bar <foo>baz <bar>fight <baz>niss ] : bar baz ;
-
-# normalize-properties
-assert_equal [ normalize-properties <a>b <c><d>e <f><g><h>i ] :
- <*><*><a>b <*><c><d>e <f><g><h>i ;
-
-# intersection
-assert_equal [ intersection 1 2 2 3 3 4 5 6 7 : 5 1 3 7 3 9 11 ] : 1 3 3 5 7 ;
-
-# is-subset
-assert_equal [ is-subset a b c : c a b d ] : true ;
-assert_equal [ is-subset a b z : c a b d ] : ;
-
-# split-path
-assert_equal [ split-path <a>b/c/<d>e ] : <a>b c <d>e ;
-assert_equal [ split-path <a>/<d>/<e> ] : <a> <d> <e> ;
-assert_equal [ split-path <a> ] : <a> ;
-assert_equal [ split-path x ] : x ;
-assert_equal [ split-path $(DOT) ] : $(DOT) ;
-assert_equal [ split-path a/b.c/d.e/f ] : a b.c d.e f ;
-if $(NT)
-{
- assert_equal [ split-path x:\\y\\z\\w ] : x: y z w ;
- assert_equal [ split-path x:\\y\\z ] : x: y z ;
- assert_equal [ split-path x:\\y ] : x: y ;
- assert_equal [ split-path x:\\ ] : x: ;
- assert_equal [ split-path x: ] : x: ;
-}
-
-# distribute-feature
-assert_equal [ distribute-feature <feature>value1 ] : <feature>value1 ;
-assert_equal [ distribute-feature <feature>value1/value2 ] : <feature>value1 <feature>value2 ;
-assert_equal [ distribute-feature <feature>value1/value2/value3 ] : <feature>value1 <feature>value2 <feature>value3 ;
-
-# segregate-free-properties
-{
- local gFREE_FEATURES = <a> <c> <e> ;
- local x = <a>b <b>c <d>e ;
- local y = <a>b <a>c <b>c <e>f ;
- local free = [ segregate-free-properties x y ] ;
- assert_equal $(free) : <a>b <a>c <e>f ;
- assert_equal $(x) : <b>c <d>e ;
- assert_equal $(y) : <b>c ;
-}
-
-# set-insert
-{
- local gTEST_SET = 1 2 3 ;
- set-insert gTEST_SET : 2 ;
- assert_equal $(gTEST_SET) : 1 2 3 ;
- set-insert gTEST_SET : 0 ;
- assert_equal $(gTEST_SET) : 1 2 3 0 ;
-}
-
-# equal-sets
-assert_equal [ equal-sets 1 2 3 : 3 2 2 1 ] : true ;
-assert_equal [ equal-sets 1 2 3 3 : 3 2 2 1 ] : true ;
-assert_equal [ equal-sets 1 2 3 3 4 : 3 2 2 1 ] : ;
-
-# segregate-overrides
-{
- local base = <a>b <c>d <e>f ;
- local overrides = <a>b <c>c <d>e <f>g ;
- segregate-overrides overrides : base ;
- assert_equal $(overrides) : <c>c <d>e <f>g ;
- assert_equal $(base) : <a>b <e>f ;
-}
-
-# select-properties
-{
- local TOOLS = gcc msvc ;
-
- local gRELEVANT_FEATURES(msvc) = <debug-symbols> <optimization> <inlining> <inline> <runtime-build> <runtime-link> <threading> <define> <undef> <include> <target-type> ;
- local gRELEVANT_FEATURES(gcc) = <runtime-link> <debug-symbols> <optimization> <inlining> <profiling> <define> <undef> <include> <shared-linkable> <target-type> ;
- local gFREE_FEATURES = <define> <undef> <include> ;
-
- local gBASE_PROPERTIES(msvc,debug) = <debug-symbols>on <inlining>off <optimization>off <runtime-build>debug <threading>single ;
- local gBASE_PROPERTIES(gcc,debug) = <debug-symbols>on <inlining>off <optimization>off <profiling>off <shared-linkable>false ;
- local gBASE_PROPERTIES(msvc,release) = <debug-symbols>off <define>NDEBUG <inlining>full <optimization>speed <runtime-build>release <threading>single ;
- local gBASE_PROPERTIES(gcc,release) = <debug-symbols>off <define>NDEBUG <inlining>full <optimization>speed <profiling>off <shared-linkable>false ;
-
- local TEST_PROPERTIES = <inlining>off <define>FOO <*><release><inlining>on
- <debug><define>DEBUG <msvc><release><foo>bar
- <gcc><*><inlining>on
- <msvc><*><foo>baz
- <msvc><release><optimization>speed
- <msvc><*><optimization>off
- <*><debug><optimization>off
- ;
-
- assert_equal_sets [ select-properties gcc debug my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <define>DEBUG <inlining>on <optimization>off ;
-
- assert_equal_sets [ select-properties gcc release my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <inlining>on ;
-
- assert_equal_sets [ select-properties msvc debug my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <define>DEBUG <inlining>off <optimization>off ;
-
- assert_equal_sets [ select-properties msvc release my-target : $(TEST_PROPERTIES) ]
- : <define>FOO <inlining>on <optimization>speed ;
-}
-
-
-# ungrist-properties
-feature TEST_FEATURE1 : a b ;
-feature TEST_FEATURE2 : c d ;
-assert_equal [ ungrist-properties <TEST_FEATURE1>a <TEST_FEATURE2>c ]
- : TEST_FEATURE1-a TEST_FEATURE2-c ;
-
-
-# fixup-path-properties
-{
- local RELATIVE_SUBDIR = foobar ;
- local gPATH_FEATURES = <include> ;
- assert_equal [ fixup-path-properties <a>b <include>.. <c>d ]
- : <include>foobar$(SLASH).. <a>b <c>d ;
-}
-# multiply-property-sets
-assert_equal [ multiply-property-sets <b>1 <a>2/3 <c>4/5 ]
- : <a>2/<b>1/<c>4 <a>2/<b>1/<c>5 <a>3/<b>1/<c>4 <a>3/<b>1/<c>5 ;
-
-# make-path-property-sets
-{
- local gUNGRISTED(<a>) = a ;
- local gUNGRISTED(<c>) = c ;
- local gUNGRISTED(<e>) = e ;
- local gUNGRISTED(<g>) = g ;
- local gUNGRISTED(<i>) = i ;
- assert_equal [ make-path-property-sets foo$(SLASH)bar : <a>b <c>d : <e>f$(SLASH)<g>h <i>j ]
- : foo$(SLASH)bar$(SLASH)e-f$(SLASH)g-h$(SLASH)<a>b$(SLASH)<c>d$(SLASH)<e>f$(SLASH)<g>h foo$(SLASH)bar$(SLASH)i-j$(SLASH)<a>b$(SLASH)<c>d$(SLASH)<i>j ;
- assert_equal [ make-path-property-sets foo$(SLASH)bar : <a>b <c>d : ]
- : foo$(SLASH)bar$(SLASH)<a>b$(SLASH)<c>d ;
-}
-
-
-# split-path-at-grist
-assert_equal
- [ split-path-at-grist <a>b$(SLASH)c$(SLASH)<d>e$(SLASH)<f>g$(SLASH)h$(SLASH)i ]
- : <a>b$(SLASH)c <d>e <f>g$(SLASH)h$(SLASH)i ;
-assert_equal
- [ split-path-at-grist b$(SLASH)c$(SLASH)<d>e$(SLASH)<f>g$(SLASH)h$(SLASH)i ]
- : b$(SLASH)c <d>e <f>g$(SLASH)h$(SLASH)i ;
-if $(NT)
-{
- assert_equal
- [ split-path-at-grist b\\c\\<include>e:\\f\\g\\<h>i ]
- : b\\c <include>e:\\f\\g <h>i ;
-}
-# directory-of
-assert_equal [ directory-of a$(SLASH)b c d$(SLASH)e$(SLASH)f ] : a . d$(SLASH)e ;
-
-# top-relative-tokens
-{
- local SUBDIR_TOKENS = a b c ;
- assert_equal [ top-relative-tokens ..$(SLASH)d$(SLASH)e ] : a b d e ;
-}
-
-# flags
-{
- local gBUILD_PROPERTIES = <a>b <c>d <e>f ;
- local FLAGS1 FLAGS2 FLAGS3 ;
- flags toolset FLAGS1 <a>b/<c>d <a>b/<e>f <x>y <a>/<c> <e> : foobar ;
- assert_equal $(FLAGS1) : foobar b d f ;
- flags toolset FLAGS2 <a> : foobar ;
- assert_equal $(FLAGS2) : b ;
- flags toolset FLAGS1 <a>b/<c>d <a>b/<e>f : foobar ;
- assert_equal $(FLAGS1) : foobar b d f foobar ;
-}
-
-# get-BUILD
-{
- local DEFAULT_BUILD = a ;
- local BUILD = b ;
- assert_equal [ get-BUILD c <d>e ] : b ;
- BUILD = ;
- assert_equal [ get-BUILD c <d>e ] : c <d>e ;
- assert_equal [ get-BUILD ] : a ;
- assert_equal [ get-BUILD <d>e ] : <d>e a ;
- BUILD = <f>g ;
- assert_equal [ get-BUILD c <d>e ] : <f>g a ;
-}
-
-# strip-initial
-assert_equal [ strip-initial a b c : a b c d e f g ] : d e f g ;
-assert_equal [ strip-initial a b c : a b d e f g ] : a b d e f g ;
-assert_equal [ strip-initial a b c : b d e f g ] : b d e f g ;
-assert_equal [ strip-initial a b c : ] : ;
-
-# simplify-path-tokens
-{
- local $(gTOP)_TOKENS = .. .. .. ;
- local gINVOCATION_SUBDIR_TOKENS = d e ;
- assert_equal [ simplify-path-tokens a b . c .. .. d e ] : a d e ;
- assert_equal [ simplify-path-tokens a b .. .. .. d e ] : .. d e ;
- assert_equal [ simplify-path-tokens .. .. d e : xxx ] : .. .. d e ;
- assert_equal [ simplify-path-tokens a b .. .. : xxx ] : xxx ;
- $(gTOP)_TOKENS = .. .. ;
- assert_equal [ simplify-path-tokens .. .. d e : xxx ] : xxx ;
- assert_equal [ simplify-path-tokens .. .. d e f g : xxx ] : f g ;
-}
diff --git a/tools/build/v2/test/unused.py b/tools/build/v2/test/unused.py
index 9db2380cd1..b44320c52e 100644
--- a/tools/build/v2/test/unused.py
+++ b/tools/build/v2/test/unused.py
@@ -17,11 +17,9 @@ 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.
-t.run_build_system()
-t.fail_test(find(t.stdout(), "warning: Unused source { b.X } in main target ./a") == -1)
+t.run_build_system(stdout="")
-t.run_build_system("-sGENERATE_ONLY_UNUSABLE=1")
-t.fail_test(find(t.stdout(), "warning: Unused source { b.X } in main target ./a") == -1)
+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.
diff --git a/tools/build/v2/test/unused/jamroot.jam b/tools/build/v2/test/unused/jamroot.jam
index 75832afd20..bc97c2b197 100644
--- a/tools/build/v2/test/unused/jamroot.jam
+++ b/tools/build/v2/test/unused/jamroot.jam
@@ -10,6 +10,7 @@ import virtual-target ;
import "class" : new ;
import modules ;
import targets ;
+import project ;
type.register X : x ;
@@ -21,21 +22,23 @@ class test-target-class : basic-target
basic-target.__init__ $(name) : $(project) ;
}
- rule construct ( source-targets * : property-set )
+ rule construct ( name : source-targets * : property-set )
{
if [ modules.peek : GENERATE_NOTHING ]
{
- return ;
+ return [ property-set.empty ] ;
}
else if [ modules.peek : GENERATE_ONLY_UNUSABLE ]
{
- return [ virtual-target.from-file b.x : $(self.project) ]
+ return [ property-set.empty ]
+ [ virtual-target.from-file b.x : . : $(self.project) ]
;
}
else
{
- return [ virtual-target.from-file b.x : $(self.project) ]
- [ virtual-target.from-file b.cpp : $(self.project) ]
+ return [ property-set.empty ]
+ [ virtual-target.from-file b.x : . : $(self.project) ]
+ [ virtual-target.from-file b.cpp : . : $(self.project) ]
;
}
}
@@ -48,7 +51,7 @@ class test-target-class : basic-target
rule make-b-main-target
{
- local project = [ CALLER_MODULE ] ;
+ local project = [ project.current ] ;
targets.main-target-alternative
[ new test-target-class b : $(project) ] ;
diff --git a/tools/build/v2/test/v1-testing/a.cpp b/tools/build/v2/test/v1-testing/a.cpp
deleted file mode 100644
index 8da76c54ec..0000000000
--- a/tools/build/v2/test/v1-testing/a.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright David Abrahams 2003-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)
-
-void foo() {}
diff --git a/tools/build/v2/test/v1-testing/b.cpp b/tools/build/v2/test/v1-testing/b.cpp
deleted file mode 100644
index 26e752aa5e..0000000000
--- a/tools/build/v2/test/v1-testing/b.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright David Abrahams 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)
-#error this does not compile.
diff --git a/tools/build/v2/test/v1-testing/boost-build.jam b/tools/build/v2/test/v1-testing/boost-build.jam
deleted file mode 100644
index d9e748ec26..0000000000
--- a/tools/build/v2/test/v1-testing/boost-build.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2002 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)
-
-TOOLS = gcc ;
-boost-build ../.. ;
diff --git a/tools/build/v2/test/v1-testing/c.cpp b/tools/build/v2/test/v1-testing/c.cpp
deleted file mode 100644
index 42f5d9c58c..0000000000
--- a/tools/build/v2/test/v1-testing/c.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright David Abrahams 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)
-#include <iostream>
-
-#ifndef RESULTCODE
-# define RESULTCODE 0
-#endif
-
-int main()
-{
- std::cout << "returning result: " << RESULTCODE << std::endl;
- return RESULTCODE;
-}
-
diff --git a/tools/build/v2/test/v1-testing/jamfile.jam b/tools/build/v2/test/v1-testing/jamfile.jam
deleted file mode 100644
index 011940f8ae..0000000000
--- a/tools/build/v2/test/v1-testing/jamfile.jam
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2002, 2003 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)
-
-import testing ;
-
-# A number of tests which should succeed
-compile a.cpp ;
-compile-fail b.cpp ;
-link-fail a.cpp : : link-no ;
-link c.cpp : : link-yes ;
-run c.cpp : : : : run-yes ;
-run-fail c.cpp : : : <define>RESULTCODE=1 : run-no ;
-
-# some tests which should fail
-
-compile-fail a.cpp : : fail-compile-no ;
-compile b.cpp : : fail-compile-yes ;
-link a.cpp : : fail-link-yes ;
-link-fail c.cpp : : fail-link-no ;
-run-fail c.cpp : : : : fail-run-no ;
-run c.cpp : : : <define>RESULTCODE=1 : fail-run-yes ;
-
-# Make sure we still fail if a dependency of an expected-failure test
-# fails.
-link-fail b.cpp : : fail-link-no-dependency ;
diff --git a/tools/build/v2/test/v1_testing.py b/tools/build/v2/test/v1_testing.py
deleted file mode 100644
index 524775fac4..0000000000
--- a/tools/build/v2/test/v1_testing.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/python
-
-# Copyright 2002 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)
-
-import BoostBuild
-import os
-from string import strip
-import re
-import time
-
-def match_re(actual,expected):
- return re.match(expected,actual,re.DOTALL) != None
-
-t = BoostBuild.Tester(match = match_re, boost_build_path = os.path.join(os.getcwd(), ".."))
-t.set_tree('v1_testing')
-
-os.environ['TOOLS'] = 'gcc'
-os.environ['NOARSCAN'] = '1'
-
-# 1) No existing bin directories. Both build and test ran fine. As
-# expected, the residue files were a bit different: There was no
-# path_test.success, and path_test.test contained the word "passed"
-# instead of the path to the .cpp file. I've haven't looked yet to
-# see if the lack of the path is a problem for reporting, but
-# hopefully the information is trivially available somewhere else.
-t.run_build_system(arguments = 'test', status = 0)
-t.expect_addition(
- ['bin/compile.test/gcc/debug/runtime-link-dynamic/compile.test'
- , 'bin/nocompile.test/gcc/debug/runtime-link-dynamic/nocompile.test'
- , 'bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-
-# 2) Missing source file for the library build. path_test.test was
-# deleted, so the reporting programs would know that failure
-# occurred. The stdout messages also indicated what had
-# happened. Excellent!
-t.rename('lib.cpp', 'lib.cpp.bak')
-t.run_build_system(arguments = 'test', status = 1)
-t.expect_removal(
- ['bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-# 3) Missing file restored. Worked fine; path_test.test was recreated,
-# no other files were touched.
-t.rename('lib.cpp.bak', 'lib.cpp')
-t.run_build_system(arguments = 'test', status = 0)
-t.expect_addition(
- [ 'bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
- # I didn't add a test for 'no other files were touched', because
- # it's a little complicated. There is an expect_nothing_more()
- # function, but we actually need to spell out a lot more than
- # what we currently have to do that.
-
-# 4) Introduced error into one of the library files, causing a library build
-# compile to fail. path_test.test was deleted, so the reporting programs
-# would know that failure occurred. Excellent! This is the case that has
-# caused regression testing to report the wrong results in the past, so it
-# was good news to see it working correctly now. We probably should figure
-# out some other test cases just to be sure it is working for full coverage.
-t.rename('lib.cpp', 'lib.cpp.bak')
-t.rename('lib-err.cpp', 'lib.cpp')
-t.touch('lib.cpp')
-t.run_build_system(arguments = 'test', status=1)
-t.expect_removal(
- ['bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-# 5) Fixed the error in the library file. The library build then worked, and
-# path_test.exe was relinked, without first recompiling path_test.obj. Test was
-# rerun. Exactly the right behavior!
-t.rename('lib.cpp.bak', 'lib.cpp')
-t.run_build_system(arguments = 'test', status = 0)
-t.expect_addition(
- [ 'bin/link.test/gcc/debug/runtime-link-dynamic/link.test'
- , 'bin/nolink.test/gcc/debug/runtime-link-dynamic/nolink.test'
- , 'bin/run.test/gcc/debug/runtime-link-dynamic/run.test'])
-
-t.cleanup()
-print 'testing complete'
diff --git a/tools/build/v2/test/v1_testing/Jamrules b/tools/build/v2/test/v1_testing/Jamrules
deleted file mode 100644
index e69de29bb2..0000000000
--- a/tools/build/v2/test/v1_testing/Jamrules
+++ /dev/null
diff --git a/tools/build/v2/test/v1_testing/boost-build.jam b/tools/build/v2/test/v1_testing/boost-build.jam
deleted file mode 100644
index d9e748ec26..0000000000
--- a/tools/build/v2/test/v1_testing/boost-build.jam
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2002 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)
-
-TOOLS = gcc ;
-boost-build ../.. ;
diff --git a/tools/build/v2/test/v1_testing/foo.cpp b/tools/build/v2/test/v1_testing/foo.cpp
deleted file mode 100644
index 6741a59439..0000000000
--- a/tools/build/v2/test/v1_testing/foo.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright David Abrahams 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)
-
-#if NOCOMPILE
-1 = 1;
-#endif
-
-void lib();
-
-void f()
-{
- lib();
-}
-
-#ifndef NOLINK
-int main()
-{
-}
-#endif
-
diff --git a/tools/build/v2/test/v1_testing/jamfile.jam b/tools/build/v2/test/v1_testing/jamfile.jam
deleted file mode 100644
index 2e0bedac7c..0000000000
--- a/tools/build/v2/test/v1_testing/jamfile.jam
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2002, 2003 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)
-
-TOOLS = $(TOOLS[1]) ;
-project-root ;
-
-# bring in rules for testing
-import testing ;
-
-lib mylib : lib.cpp ;
-
-compile foo.cpp : : compile ;
-compile-fail foo.cpp : <define>NOCOMPILE : nocompile ;
-
-link foo.cpp <lib>mylib : : link ;
-link-fail foo.cpp <lib>mylib : <define>NOLINK : nolink ;
-
-run foo.cpp <lib>mylib
- : # args
- : # input-files
- : <define>RUN
- : run ;
diff --git a/tools/build/v2/test/v1_testing/jamroot.jam b/tools/build/v2/test/v1_testing/jamroot.jam
deleted file mode 100644
index fe69424588..0000000000
--- a/tools/build/v2/test/v1_testing/jamroot.jam
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2002 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)
-
-# just label the project root
diff --git a/tools/build/v2/test/v1_testing/lib-err.cpp b/tools/build/v2/test/v1_testing/lib-err.cpp
deleted file mode 100644
index 060fd73e56..0000000000
--- a/tools/build/v2/test/v1_testing/lib-err.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright David Abrahams 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)
-
-3 = 4;
-void lib() {}
diff --git a/tools/build/v2/test/v1_testing/lib.cpp b/tools/build/v2/test/v1_testing/lib.cpp
deleted file mode 100644
index 1472b96ad5..0000000000
--- a/tools/build/v2/test/v1_testing/lib.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright David Abrahams 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)
-
-void lib() {}
diff --git a/tools/build/v2/tools/auto-index.jam b/tools/build/v2/tools/auto-index.jam
index ebbf344eba..5c5c1d06cf 100644
--- a/tools/build/v2/tools/auto-index.jam
+++ b/tools/build/v2/tools/auto-index.jam
@@ -11,8 +11,8 @@ feature.feature auto-index : off "on" ;
feature.feature auto-index-internal : off "on" ;
feature.feature auto-index-verbose : off "on" ;
feature.feature auto-index-no-duplicates : off "on" ;
-feature.feature auto-index-script : : free ;
-feature.feature auto-index-prefix : : free ;
+feature.feature auto-index-script : : free path ;
+feature.feature auto-index-prefix : : free path ;
feature.feature auto-index-type : : free ;
feature.feature auto-index-section-names : "on" off ;
diff --git a/tools/build/v2/tools/boostbook.jam b/tools/build/v2/tools/boostbook.jam
index 3a5964c627..3ab0debdb0 100644
--- a/tools/build/v2/tools/boostbook.jam
+++ b/tools/build/v2/tools/boostbook.jam
@@ -336,6 +336,9 @@ rule find-tools ( docbook-xsl-dir ? : docbook-dtd-dir ? : boostbook-dir ? )
# 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)
diff --git a/tools/build/v2/tools/builtin.py b/tools/build/v2/tools/builtin.py
index 31a7bffeef..5b28a0aa78 100644
--- a/tools/build/v2/tools/builtin.py
+++ b/tools/build/v2/tools/builtin.py
@@ -144,11 +144,20 @@ def register_globals ():
feature.feature ('threading', ['single', 'multi'], ['propagated'])
feature.feature ('rtti', ['on', 'off'], ['propagated'])
feature.feature ('exception-handling', ['on', 'off'], ['propagated'])
+
+ # Whether there is support for asynchronous EH (e.g. catching SEGVs).
+ feature.feature ('asynch-exceptions', ['on', 'off'], ['propagated'])
+
+ # Whether all extern "C" functions are considered nothrow by default.
+ feature.feature ('extern-c-nothrow', ['off', 'on'], ['propagated'])
+
feature.feature ('debug-symbols', ['on', 'off'], ['propagated'])
feature.feature ('define', [], ['free'])
+ feature.feature ('undef', [], ['free'])
feature.feature ('include', [], ['free', 'path']) #order-sensitive
feature.feature ('cflags', [], ['free'])
feature.feature ('cxxflags', [], ['free'])
+ feature.feature ('asmflags', [], ['free'])
feature.feature ('linkflags', [], ['free'])
feature.feature ('archiveflags', [], ['free'])
feature.feature ('version', [], ['free'])
@@ -309,10 +318,6 @@ def register_globals ():
variant ('release', ['<optimization>speed', '<debug-symbols>off', '<inlining>full',
'<runtime-debugging>off', '<define>NDEBUG'])
variant ('profile', ['release'], ['<profiling>on', '<debug-symbols>on'])
-
- type.register ('H', ['h'])
- type.register ('HPP', ['hpp'], 'H')
- type.register ('C', ['c'])
reset ()
@@ -348,8 +353,11 @@ class SearchedLibTarget (virtual_target.AbstractFileTarget):
class CScanner (scanner.Scanner):
def __init__ (self, includes):
scanner.Scanner.__init__ (self)
-
- self.includes_ = includes
+
+ self.includes_ = []
+
+ for i in includes:
+ self.includes_.extend(i.split("&&"))
def pattern (self):
return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")'
@@ -399,7 +407,7 @@ class LibGenerator (generators.Generator):
SHARED_LIB.
"""
- def __init__(self, id = 'LibGenerator', composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
+ def __init__(self, id, composing = True, source_types = [], target_types_and_names = ['LIB'], requirements = []):
generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements)
def run(self, project, name, prop_set, sources):
@@ -432,7 +440,9 @@ class LibGenerator (generators.Generator):
def viable_source_types(self):
return ['*']
-generators.register(LibGenerator())
+generators.register(LibGenerator("builtin.lib-generator"))
+
+generators.override("builtin.prebuilt", "builtin.lib-generator")
def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]):
"""The implementation of the 'lib' rule. Beyond standard syntax that rule allows
@@ -508,22 +518,19 @@ class SearchedLibGenerator (generators.Generator):
generators.register (SearchedLibGenerator ())
-### class prebuilt-lib-generator : generator
-### {
-### rule __init__ ( * : * )
-### {
-### generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
-### }
-###
-### rule run ( project name ? : prop_set : sources * : multiple ? )
-### {
-### local f = [ $(prop_set).get <file> ] ;
-### return $(f) $(sources) ;
-### }
-### }
-###
-### generators.register
-### [ new prebuilt-lib-generator builtin.prebuilt : : LIB : <file> ] ;
+class PrebuiltLibGenerator(generators.Generator):
+
+ def __init__(self, id, composing, source_types, target_types_and_names, requirements):
+ generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
+
+ def run(self, project, name, properties, sources):
+ f = properties.get("file")
+ return f + sources
+
+generators.register(PrebuiltLibGenerator("builtin.prebuilt", False, [],
+ ["LIB"], ["<file>"]))
+
+generators.override("builtin.prebuilt", "builtin.lib-generator")
class CompileAction (virtual_target.Action):
@@ -565,9 +572,8 @@ class LinkingGenerator (generators.Generator):
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
def run (self, project, name, prop_set, sources):
-
- lib_sources = prop_set.get('<library>')
- sources.extend(lib_sources)
+
+ sources.extend(prop_set.get('<library>'))
# Add <library-path> properties for all searched libraries
extra = []
@@ -576,38 +582,41 @@ class LinkingGenerator (generators.Generator):
search = s.search()
extra.extend(property.Property('<library-path>', sp) for sp in search)
- orig_xdll_path = []
-
- if prop_set.get('<hardcode-dll-paths>') == ['true'] \
- and type.is_derived(self.target_types_ [0], 'EXE'):
- xdll_path = prop_set.get('<xdll-path>')
- orig_xdll_path = [ replace_grist(x, '<dll-path>') for x in xdll_path ]
- # It's possible that we have libraries in sources which did not came
- # from 'lib' target. For example, libraries which are specified
- # just as filenames as sources. We don't have xdll-path properties
- # for such target, but still need to add proper dll-path properties.
- for s in sources:
+ # It's possible that we have libraries in sources which did not came
+ # from 'lib' target. For example, libraries which are specified
+ # just as filenames as sources. We don't have xdll-path properties
+ # for such target, but still need to add proper dll-path properties.
+ extra_xdll_path = []
+ for s in sources:
if type.is_derived (s.type (), 'SHARED_LIB') and not s.action ():
# Unfortunately, we don't have a good way to find the path
# to a file, so use this nasty approach.
p = s.project()
- location = path.root(s.name(), p.get('source-location'))
- xdll_path.append(path.parent(location))
-
- extra.extend(property.Property('<dll-path>', sp) for sp in xdll_path)
+ location = path.root(s.name(), p.get('source-location')[0])
+ extra_xdll_path.append(os.path.dirname(location))
+
+ # Hardcode DLL paths only when linking executables.
+ # Pros: do not need to relink libraries when installing.
+ # Cons: "standalone" libraries (plugins, python extensions) can not
+ # hardcode paths to dependent libraries.
+ if prop_set.get('<hardcode-dll-paths>') == ['true'] \
+ and type.is_derived(self.target_types_ [0], 'EXE'):
+ xdll_path = prop_set.get('<xdll-path>')
+ extra.extend(property.Property('<dll-path>', sp) \
+ for sp in extra_xdll_path)
+ extra.extend(property.Property('<dll-path>', sp) \
+ for sp in xdll_path)
if extra:
- prop_set = prop_set.add_raw (extra)
-
+ prop_set = prop_set.add_raw (extra)
result = generators.Generator.run(self, project, name, prop_set, sources)
-
+
if result:
ur = self.extra_usage_requirements(result, prop_set)
- ur = ur.add(property_set.create(orig_xdll_path))
+ ur = ur.add(property_set.create(['<xdll-path>' + p for p in extra_xdll_path]))
else:
return None
-
- return(ur, result)
+ return (ur, result)
def extra_usage_requirements (self, created_targets, prop_set):
@@ -696,20 +705,18 @@ class ArchiveGenerator (generators.Generator):
return result
-### rule register-archiver ( id composing ? : source_types + : target_types + :
-### requirements * )
-### {
-### local g = [ new ArchiveGenerator $(id) $(composing) : $(source_types)
-### : $(target_types) : $(requirements) ] ;
-### generators.register $(g) ;
-### }
-###
-###
-### IMPORT $(__name__) : register-linker register-archiver
-### : : generators.register-linker generators.register-archiver ;
-###
-###
-###
+
+def register_archiver(id, source_types, target_types, requirements):
+ g = ArchiveGenerator(id, True, source_types, target_types, requirements)
+ generators.register(g)
+
+class DummyGenerator(generators.Generator):
+ """Generator that accepts everything and produces nothing. Useful as a general
+ fallback for toolset-specific actions like PCH generation.
+ """
+ def run (self, project, name, prop_set, sources):
+ return (property_set.empty(), [])
+
get_manager().projects().add_rule("variant", variant)
diff --git a/tools/build/v2/tools/cast.jam b/tools/build/v2/tools/cast.jam
index 6c84922f1f..211ce63296 100644
--- a/tools/build/v2/tools/cast.jam
+++ b/tools/build/v2/tools/cast.jam
@@ -11,7 +11,7 @@
#
# exe main : main.cpp [ cast _ moccable-cpp : widget.cpp ] ;
#
-# Boost.Build will assing target type CPP to both main.cpp and widget.cpp. Then,
+# Boost.Build will assign target type CPP to both main.cpp and widget.cpp. Then,
# the cast rule will change target type of widget.cpp to MOCCABLE-CPP, and Qt
# support will run the MOC tool as part of the build process.
#
diff --git a/tools/build/v2/tools/common.jam b/tools/build/v2/tools/common.jam
index df914d9d46..53e91b428f 100644
--- a/tools/build/v2/tools/common.jam
+++ b/tools/build/v2/tools/common.jam
@@ -334,7 +334,7 @@ rule get-absolute-tool-path ( command )
# first path found. Otherwise, returns an empty string. If 'path-last' is
# specified, PATH is searched after 'additional-paths'.
#
-local rule find-tool ( name : additional-paths * : path-last ? )
+rule find-tool ( name : additional-paths * : path-last ? )
{
local path = [ path.programs-path ] ;
local match = [ path.glob $(path) : $(name) $(name).exe ] ;
@@ -961,25 +961,22 @@ rule __test__ ( )
{
import assert ;
- local nl = "
-" ;
-
local save-os = [ modules.peek os : .name ] ;
modules.poke os : .name : LINUX ;
- assert.result "PATH=\"foo:bar:baz\"$(nl)export PATH$(nl)"
+ assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
: path-variable-setting-command PATH : foo bar baz ;
- assert.result "PATH=\"foo:bar:$PATH\"$(nl)export PATH$(nl)"
+ 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$(nl)"
+ assert.result "set PATH=foo;bar;baz\n"
: path-variable-setting-command PATH : foo bar baz ;
- assert.result "set PATH=foo;bar;%PATH%$(nl)"
+ assert.result "set PATH=foo;bar;%PATH%\n"
: prepend-path-variable-command PATH : foo bar ;
modules.poke os : .name : $(save-os) ;
diff --git a/tools/build/v2/tools/common.py b/tools/build/v2/tools/common.py
index 612745b81f..3eb0f7d3f1 100644
--- a/tools/build/v2/tools/common.py
+++ b/tools/build/v2/tools/common.py
@@ -53,7 +53,7 @@ def reset ():
if OS == "NT":
# On Windows the case and capitalization of PATH is not always predictable, so
# let's find out what variable name was really set.
- for n in sys.environ:
+ for n in os.environ:
if n.lower() == "path":
__executable_path_variable = n
break
@@ -99,7 +99,7 @@ class Configurations(object):
def __init__(self):
self.used_ = set()
self.all_ = set()
- self.params = {}
+ self.params_ = {}
def register(self, id):
"""
@@ -113,7 +113,7 @@ class Configurations(object):
errors.error("common: the configuration '$(id)' is in use")
if id not in self.all_:
- self.all_ += [id]
+ self.all_.add(id)
# Indicate that a new configuration has been added.
return True
@@ -133,7 +133,7 @@ class Configurations(object):
errors.error("common: the configuration '$(id)' is not known")
if id not in self.used_:
- self.used_ += [id]
+ self.used_.add(id)
# indicate that the configuration has been marked as 'used'
return True
@@ -150,7 +150,7 @@ class Configurations(object):
def get(self, id, param):
""" Returns the value of a configuration parameter. """
- self.params_.getdefault(param, {}).getdefault(id, None)
+ return self.params_.get(param, {}).get(id)
def set (self, id, param, value):
""" Sets the value of a configuration parameter. """
@@ -294,6 +294,8 @@ def get_invocation_command_nodefault(
#print "warning: initialized from" [ errors.nearest-user-location ] ;
else:
command = check_tool(user_provided_command)
+ assert(isinstance(command, list))
+ command=' '.join(command)
if not command and __debug_configuration:
print "warning: toolset", toolset, "initialization:"
print "warning: can't find user-provided command", user_provided_command
@@ -347,7 +349,9 @@ def get_absolute_tool_path(command):
programs = path.programs_path()
m = path.glob(programs, [command, command + '.exe' ])
if not len(m):
- print "Could not find:", command, "in", programs
+ if __debug_configuration:
+ print "Could not find:", command, "in", programs
+ return None
return os.path.dirname(m[0])
# ported from trunk@47174
diff --git a/tools/build/v2/tools/cray.jam b/tools/build/v2/tools/cray.jam
new file mode 100644
index 0000000000..1d5271e972
--- /dev/null
+++ b/tools/build/v2/tools/cray.jam
@@ -0,0 +1,112 @@
+# Copyright 2001 David Abrahams.
+# Copyright 2004, 2005 Markus Schoepflin.
+# Copyright 2011, John Maddock
+# 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)
+
+#
+# Cray C++ Compiler
+# See http://docs.cray.com/books/S-2179-50/html-S-2179-50/S-2179-50-toc.html
+#
+
+import feature generators common ;
+import toolset : flags ;
+
+feature.extend toolset : cray ;
+
+# Inherit from Unix toolset to get library ordering magic.
+toolset.inherit cray : unix ;
+
+generators.override cray.prebuilt : builtin.lib-generator ;
+generators.override cray.prebuilt : builtin.prebuilt ;
+generators.override cray.searched-lib-generator : searched-lib-generator ;
+
+
+rule init ( version ? : command * : options * )
+{
+ local condition = [ common.check-init-parameters cray : version $(version) ] ;
+
+ local command = [ common.get-invocation-command cray : CC : $(command) ] ;
+
+ if $(command)
+ {
+ local root = [ common.get-absolute-tool-path $(command[-1]) ] ;
+
+ if $(root)
+ {
+ flags cray .root $(condition) : "\"$(root)\"/" ;
+ }
+ }
+ # If we can't find 'CC' anyway, at least show 'CC' in the commands
+ command ?= CC ;
+
+ common.handle-options cray : $(condition) : $(command) : $(options) ;
+}
+
+generators.register-c-compiler cray.compile.c++ : CPP : OBJ : <toolset>cray ;
+generators.register-c-compiler cray.compile.c : C : OBJ : <toolset>cray ;
+
+
+
+# No static linking as far as I can tell.
+# flags cxx LINKFLAGS <runtime-link>static : -bstatic ;
+flags cray.compile OPTIONS <debug-symbols>on : -Gn ;
+flags cray.link OPTIONS <debug-symbols>on : -Gn ;
+
+flags cray.compile OPTIONS <optimization>off : -O0 ;
+flags cray.compile OPTIONS <optimization>speed : -O3 ;
+flags cray.compile OPTIONS <optimization>space : -O1 ;
+
+flags cray.compile OPTIONS <cflags> ;
+flags cray.compile.c++ OPTIONS <cxxflags> ;
+flags cray.compile DEFINES <define> ;
+flags cray.compile INCLUDES <include> ;
+flags cray.link OPTIONS <linkflags> ;
+
+flags cray.link LIBPATH <library-path> ;
+flags cray.link LIBRARIES <library-file> ;
+flags cray.link FINDLIBS-ST <find-static-library> ;
+flags cray.link FINDLIBS-SA <find-shared-library> ;
+
+actions link bind LIBRARIES
+{
+ $(CONFIG_COMMAND) $(OPTIONS) -o "$(<)" -L$(LIBPATH) "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-ST) -l$(FINDLIBS-SA)
+}
+
+# When creating dynamic libraries, we don't want to be warned about unresolved
+# symbols, therefore all unresolved symbols are marked as expected by
+# '-expect_unresolved *'. This also mirrors the behaviour of the GNU tool
+# chain.
+
+actions link.dll bind LIBRARIES
+{
+ $(CONFIG_COMMAND) -shared $(OPTIONS) -o "$(<[1])" -L$(LIBPATH) "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-ST) -l$(FINDLIBS-SA)
+}
+
+
+# Note: Relaxed ANSI mode (-std) is used for compilation because in strict ANSI
+# C89 mode (-std1) the compiler doesn't accept C++ comments in C files. As -std
+# is the default, no special flag is needed.
+actions compile.c
+{
+ $(.root:E=)cc -c $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -o "$(<)" "$(>)"
+}
+
+# Note: The compiler is forced to compile the files as C++ (-x cxx) because
+# otherwise it will silently ignore files with no file extension.
+#
+# Note: We deliberately don't suppress any warnings on the compiler command
+# line, the user can always do this in a customized toolset later on.
+
+actions compile.c++
+{
+ $(CONFIG_COMMAND) -c -h gnu $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -o "$(<)" "$(>)"
+}
+
+# Always create archive from scratch. See the gcc toolet for rationale.
+RM = [ common.rm-command ] ;
+actions together piecemeal archive
+{
+ $(RM) "$(<)"
+ ar rc $(<) $(>)
+}
diff --git a/tools/build/v2/tools/darwin.jam b/tools/build/v2/tools/darwin.jam
index 283dface94..dd6eacb114 100644
--- a/tools/build/v2/tools/darwin.jam
+++ b/tools/build/v2/tools/darwin.jam
@@ -231,7 +231,7 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? )
{
if $(.debug-configuration)
{
- ECHO notice: available sdk for $(condition)/<macosx-version>$(version-feature) at $(sdk) ;
+ ECHO notice: available sdk for $(condition)/<macosx-version>$(version-feature) at $(root) ;
}
# Add the version to the features for specifying them.
@@ -247,9 +247,9 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? )
# Set the flags the version needs to compile with, first
# generic options.
flags darwin.compile OPTIONS $(condition)/<macosx-version>$(version-feature)
- : -isysroot $(sdk) ;
+ : -isysroot $(root) ;
flags darwin.link OPTIONS $(condition)/<macosx-version>$(version-feature)
- : -isysroot $(sdk) ;
+ : -isysroot $(root) ;
# Then device variation options.
switch $(version[1])
@@ -287,13 +287,28 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? )
}
}
- return $(version-feature) ;
+ if $(version[3]) > 0
+ {
+ # We have a minor version of an SDK. We want to set up
+ # previous minor versions, plus the current minor version.
+ # So we recurse to set up the previous minor versions, up to
+ # the current version.
+ local minor-minus-1 = [ CALC $(version[3]) - 1 ] ;
+ return
+ [ init-sdk $(condition) : $(root)
+ : $(version[1-2]) $(minor-minus-1) : [ version-to-feature $(version[1-2]) $(minor-minus-1) ] ]
+ $(version-feature) ;
+ }
+ else
+ {
+ return $(version-feature) ;
+ }
}
else if $(version[4])
{
# We have a patch version of an SDK. We want to set up
# both the specific patch version, and the minor version.
- # So we recurse to set up the minor version. Plus the minor version.
+ # So we recurse to set up the patch version. Plus the minor version.
return
[ init-sdk $(condition) : $(root)
: $(version[1-3]) : [ version-to-feature $(version[1-3]) ] ]
@@ -498,7 +513,7 @@ flags darwin.link OPTIONS <optimization>space : -Wl,-dead_strip -no_dead_strip_i
flags darwin.compile OPTIONS <link>shared : -dynamic ;
# Misc options.
-flags darwin.compile OPTIONS : -no-cpp-precomp -gdwarf-2 -fexceptions ;
+flags darwin.compile OPTIONS : -gdwarf-2 -fexceptions ;
#~ flags darwin.link OPTIONS : -fexceptions ;
# Add the framework names to use.
diff --git a/tools/build/v2/tools/docutils.jam b/tools/build/v2/tools/docutils.jam
index bf0616174b..fc775b6fc3 100644
--- a/tools/build/v2/tools/docutils.jam
+++ b/tools/build/v2/tools/docutils.jam
@@ -56,6 +56,7 @@ rule init ( docutils-dir ? : tools-dir ? )
.setup = [
common.prepend-path-variable-command PYTHONPATH
: $(.docutils-dir) $(.docutils-dir)/extras ] ;
+ RST2XXX = [ common.find-tool rst2html ] ;
}
}
diff --git a/tools/build/v2/tools/gcc.jam b/tools/build/v2/tools/gcc.jam
index f7b0da542e..ee3aae128a 100644
--- a/tools/build/v2/tools/gcc.jam
+++ b/tools/build/v2/tools/gcc.jam
@@ -446,13 +446,17 @@ rule setup-address-model ( targets * : sources * : properties * )
}
else
{
- if $(model) = 32
- {
- option = -m32 ;
- }
- else if $(model) = 64
+ local arch = [ feature.get-values architecture : $(properties) ] ;
+ if $(arch) != arm
{
- option = -m64 ;
+ if $(model) = 32
+ {
+ option = -m32 ;
+ }
+ else if $(model) = 64
+ {
+ option = -m64 ;
+ }
}
# For darwin, the model can be 32_64. darwin.jam will handle that
# on its own.
@@ -1097,9 +1101,10 @@ local rule cpu-flags ( toolset variable : architecture : instruction-set + : val
#
# x86 and compatible
# The 'native' option appeared in gcc 4.2 so we cannot safely use it
-# as default. Use conservative i386 instead.
+# as default. Use conservative i386 instead for 32-bit.
+toolset.flags gcc OPTIONS <architecture>x86/<address-model>32/<instruction-set> : -march=i386 ;
cpu-flags gcc OPTIONS : x86 : native : -march=native ;
-cpu-flags gcc OPTIONS : x86 : i386 : -march=i386 : default ;
+cpu-flags gcc OPTIONS : x86 : i386 : -march=i386 ;
cpu-flags gcc OPTIONS : x86 : i486 : -march=i486 ;
cpu-flags gcc OPTIONS : x86 : i586 : -march=i586 ;
cpu-flags gcc OPTIONS : x86 : i686 : -march=i686 ;
diff --git a/tools/build/v2/tools/gcc.py b/tools/build/v2/tools/gcc.py
index 2a3e675ef1..b0aba1d293 100644
--- a/tools/build/v2/tools/gcc.py
+++ b/tools/build/v2/tools/gcc.py
@@ -23,13 +23,16 @@ import re
import bjam
from b2.tools import unix, common, rc, pch, builtin
-from b2.build import feature, type, toolset, generators
+from b2.build import feature, type, toolset, generators, property_set
+from b2.build.property import Property
from b2.util.utility import os_name, on_windows
from b2.manager import get_manager
from b2.build.generators import Generator
from b2.build.toolset import flags
from b2.util.utility import to_seq
+
+
__debug = None
def debug():
@@ -222,12 +225,12 @@ class GccPchGenerator(pch.PchGenerator):
# Find the header in sources. Ignore any CPP sources.
header = None
for s in sources:
- if type.is_derived(s.type, 'H'):
+ if type.is_derived(s.type(), 'H'):
header = s
# Error handling: Base header file name should be the same as the base
# precompiled header name.
- header_name = header.name
+ header_name = header.name()
header_basename = os.path.basename(header_name).rsplit('.', 1)[0]
if header_basename != name:
location = project.project_module
@@ -239,14 +242,15 @@ class GccPchGenerator(pch.PchGenerator):
# return result of base class and pch-file property as usage-requirements
# FIXME: what about multiple results from generator.run?
- return (property_set.create('<pch-file>' + pch_file[0], '<cflags>-Winvalid-pch'),
+ return (property_set.create([Property('pch-file', pch_file[0]),
+ Property('cflags', '-Winvalid-pch')]),
pch_file)
# Calls the base version specifying source's name as the name of the created
# target. As result, the PCH will be named whatever.hpp.gch, and not
# whatever.gch.
def generated_targets(self, sources, prop_set, project, name = None):
- name = sources[0].name
+ name = sources[0].name()
return Generator.generated_targets(self, sources,
prop_set, project, name)
diff --git a/tools/build/v2/tools/intel-win.jam b/tools/build/v2/tools/intel-win.jam
index 691b5dce98..c9adac0d96 100644
--- a/tools/build/v2/tools/intel-win.jam
+++ b/tools/build/v2/tools/intel-win.jam
@@ -161,8 +161,8 @@ rule init ( version ? : # the compiler version
if ! $(compatibility)
{
- # If there's no backend version, assume 7.1.
- compatibility = vc7.1 ;
+ # If there's no backend version, assume 10.
+ compatibility = vc10 ;
}
local extract-version = [ MATCH ^vc(.*) : $(compatibility) ] ;
diff --git a/tools/build/v2/tools/mc.py b/tools/build/v2/tools/mc.py
new file mode 100644
index 0000000000..c194acdff7
--- /dev/null
+++ b/tools/build/v2/tools/mc.py
@@ -0,0 +1,46 @@
+# Copyright (c) 2005 Alexey Pakhunov.
+# Copyright (c) 2011 Juraj Ivancic
+#
+# 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)
+
+# Support for Microsoft message compiler tool.
+# Notes:
+# - there's just message compiler tool, there's no tool for
+# extracting message strings from sources
+# - This file allows to use Microsoft message compiler
+# with any toolset. In msvc.jam, there's more specific
+# message compiling action.
+
+import bjam
+
+from b2.tools import common, rc
+from b2.build import generators, type
+from b2.build.toolset import flags
+from b2.build.feature import feature
+from b2.manager import get_manager
+
+def init():
+ pass
+
+type.register('MC', ['mc'])
+
+
+# Command line options
+feature('mc-input-encoding', ['ansi', 'unicode'], ['free'])
+feature('mc-output-encoding', ['unicode', 'ansi'], ['free'])
+feature('mc-set-customer-bit', ['no', 'yes'], ['free'])
+
+flags('mc.compile', 'MCFLAGS', ['<mc-input-encoding>ansi'], ['-a'])
+flags('mc.compile', 'MCFLAGS', ['<mc-input-encoding>unicode'], ['-u'])
+flags('mc.compile', 'MCFLAGS', ['<mc-output-encoding>ansi'], '-A')
+flags('mc.compile', 'MCFLAGS', ['<mc-output-encoding>unicode'], ['-U'])
+flags('mc.compile', 'MCFLAGS', ['<mc-set-customer-bit>no'], [])
+flags('mc.compile', 'MCFLAGS', ['<mc-set-customer-bit>yes'], ['-c'])
+
+generators.register_standard('mc.compile', ['MC'], ['H', 'RC'])
+
+get_manager().engine().register_action(
+ 'mc.compile',
+ 'mc $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"')
diff --git a/tools/build/v2/tools/midl.py b/tools/build/v2/tools/midl.py
new file mode 100644
index 0000000000..45811d16bc
--- /dev/null
+++ b/tools/build/v2/tools/midl.py
@@ -0,0 +1,134 @@
+# Copyright (c) 2005 Alexey Pakhunov.
+# Copyright (c) 2011 Juraj Ivancic
+#
+# 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)
+
+# Microsoft Interface Definition Language (MIDL) related routines
+from b2.build import scanner, type
+from b2.build.toolset import flags
+from b2.build.feature import feature
+from b2.manager import get_manager
+from b2.tools import builtin, common
+from b2.util import regex
+
+def init():
+ pass
+
+type.register('IDL', ['idl'])
+
+# A type library (.tlb) is generated by MIDL compiler and can be included
+# to resources of an application (.rc). In order to be found by a resource
+# compiler its target type should be derived from 'H' - otherwise
+# the property '<implicit-dependency>' will be ignored.
+type.register('MSTYPELIB', 'tlb', 'H')
+
+# Register scanner for MIDL files
+class MidlScanner(scanner.Scanner):
+ def __init__ (self, includes=[]):
+ scanner.Scanner.__init__(self)
+ self.includes = includes
+
+ # List of quoted strings
+ re_strings = "[ \t]*\"([^\"]*)\"([ \t]*,[ \t]*\"([^\"]*)\")*[ \t]*" ;
+
+ # 'import' and 'importlib' directives
+ self.re_import = "import" + re_strings + "[ \t]*;" ;
+ self.re_importlib = "importlib[ \t]*[(]" + re_strings + "[)][ \t]*;" ;
+
+ # C preprocessor 'include' directive
+ self.re_include_angle = "#[ \t]*include[ \t]*<(.*)>" ;
+ self.re_include_quoted = "#[ \t]*include[ \t]*\"(.*)\"" ;
+
+ def pattern():
+ # Match '#include', 'import' and 'importlib' directives
+ return "((#[ \t]*include|import(lib)?).+(<(.*)>|\"(.*)\").+)"
+
+ def process(self, target, matches, binding):
+ included_angle = regex.transform(matches, self.re_include_angle)
+ included_quoted = regex.transform(matches, self.re_include_quoted)
+ imported = regex.transform(matches, self.re_import, [1, 3])
+ imported_tlbs = regex.transform(matches, self.re_importlib, [1, 3])
+
+ # CONSIDER: the new scoping rule seem to defeat "on target" variables.
+ g = bjam.call('get-target-variable', target, 'HDRGRIST')
+ b = os.path.normalize_path(os.path.dirname(binding))
+
+ # 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.
+ g2 = g + "#" + b
+
+ g = "<" + g + ">"
+ g2 = "<" + g2 + ">"
+
+ included_angle = [ g + x for x in included_angle ]
+ included_quoted = [ g + x for x in included_quoted ]
+ imported = [ g + x for x in imported ]
+ imported_tlbs = [ g + x for x in imported_tlbs ]
+
+ all = included_angle + included_quoted + imported
+
+ bjam.call('INCLUDES', [target], all)
+ bjam.call('DEPENDS', [target], imported_tlbs)
+ bjam.call('NOCARE', all + imported_tlbs)
+ engine.set_target_variable(included_angle , 'SEARCH', ungrist(self.includes))
+ engine.set_target_variable(included_quoted, 'SEARCH', b + ungrist(self.includes))
+ engine.set_target_variable(imported , 'SEARCH', b + ungrist(self.includes))
+ engine.set_target_variable(imported_tlbs , 'SEARCH', b + ungrist(self.includes))
+
+ get_manager().scanners().propagate(type.get_scanner('CPP', PropertySet(self.includes)), included_angle + included_quoted)
+ get_manager().scanners().propagate(self, imported)
+
+scanner.register(MidlScanner, 'include')
+type.set_scanner('IDL', MidlScanner)
+
+
+# Command line options
+feature('midl-stubless-proxy', ['yes', 'no'], ['propagated'] )
+feature('midl-robust', ['yes', 'no'], ['propagated'] )
+
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>yes'], ['/Oicf' ])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-stubless-proxy>no' ], ['/Oic' ])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>yes' ], ['/robust' ])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<midl-robust>no' ], ['/no_robust'])
+
+# Architecture-specific options
+architecture_x86 = ['<architecture>' , '<architecture>x86']
+address_model_32 = ['<address-model>', '<address-model>32']
+address_model_64 = ['<address-model>', '<address-model>64']
+
+flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/' + m for ar in architecture_x86 for m in address_model_32 ], ['/win32'])
+flags('midl.compile.idl', 'MIDLFLAGS', [ar + '/<address-model>64' for ar in architecture_x86], ['/x64'])
+flags('midl.compile.idl', 'MIDLFLAGS', ['<architecture>ia64/' + m for m in address_model_64], ['/ia64'])
+
+flags('midl.compile.idl', 'DEFINES', [], ['<define>'])
+flags('midl.compile.idl', 'UNDEFS', [], ['<undef>'])
+flags('midl.compile.idl', 'INCLUDES', [], ['<include>'])
+
+
+builtin.register_c_compiler('midl.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], [])
+
+
+# MIDL does not always generate '%_proxy.c' and '%_dlldata.c'. This behavior
+# depends on contents of the source IDL file. Calling TOUCH_FILE below ensures
+# that both files will be created so bjam will not try to recreate them
+# constantly.
+get_manager().engine().register_action(
+ 'midl.compile.idl',
+ '''midl /nologo @"@($(<[1]:W).rsp:E=
+"$(>:W)"
+-D$(DEFINES)
+"-I$(INCLUDES)"
+-U$(UNDEFS)
+$(MIDLFLAGS)
+/tlb "$(<[1]:W)"
+/h "$(<[2]:W)"
+/iid "$(<[3]:W)"
+/proxy "$(<[4]:W)"
+/dlldata "$(<[5]:W)")"
+{touch} "$(<[4]:W)"
+{touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command()))
diff --git a/tools/build/v2/tools/msvc.jam b/tools/build/v2/tools/msvc.jam
index e33a66d22b..22548323ad 100644
--- a/tools/build/v2/tools/msvc.jam
+++ b/tools/build/v2/tools/msvc.jam
@@ -736,7 +736,11 @@ local rule configure-really ( version ? : options * )
# version from the path.
# FIXME: We currently detect both Microsoft Visual Studio 9.0 and
# 9.0express as 9.0 here.
- if [ MATCH "(Microsoft Visual Studio 10)" : $(command) ]
+ if [ MATCH "(Microsoft Visual Studio 11)" : $(command) ]
+ {
+ version = 11.0 ;
+ }
+ else if [ MATCH "(Microsoft Visual Studio 10)" : $(command) ]
{
version = 10.0 ;
}
@@ -1351,7 +1355,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
# Known toolset versions, in order of preference.
-.known-versions = 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 ;
@@ -1360,6 +1364,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
.version-alias-8 = 8.0 ;
.version-alias-9 = 9.0 ;
.version-alias-10 = 10.0 ;
+.version-alias-11 = 11.0 ;
# Names of registry keys containing the Visual C++ installation path (relative
# to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft").
@@ -1372,6 +1377,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
.version-9.0express-reg = "VCExpress\\9.0\\Setup\\VC" ;
.version-10.0-reg = "VisualStudio\\10.0\\Setup\\VC" ;
.version-10.0express-reg = "VCExpress\\10.0\\Setup\\VC" ;
+.version-11.0-reg = "VisualStudio\\11.0\\Setup\\VC" ;
# Visual C++ Toolkit 2003 does not store its installation path in the registry.
# The environment variable 'VCToolkitInstallDir' and the default installation
diff --git a/tools/build/v2/tools/msvc.py b/tools/build/v2/tools/msvc.py
new file mode 100644
index 0000000000..f4448daab4
--- /dev/null
+++ b/tools/build/v2/tools/msvc.py
@@ -0,0 +1,1198 @@
+# 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
+# Copyright (c) 2011 Juraj Ivancic
+#
+# 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)
+
+################################################################################
+#
+# MSVC Boost Build toolset module.
+# --------------------------------
+#
+# All toolset versions need to have their location either auto-detected or
+# explicitly specified except for the special 'default' version that expects the
+# environment to find the needed tools or report an error.
+#
+################################################################################
+
+from os import environ
+import os.path
+import re
+import _winreg
+
+import bjam
+
+from b2.tools import common, rc, pch, builtin, mc, midl
+from b2.build import feature, type, toolset, generators, property_set
+from b2.build.property import Property
+from b2.util import path
+from b2.manager import get_manager
+from b2.build.generators import Generator
+from b2.build.toolset import flags
+from b2.util.utility import to_seq, on_windows
+from b2.tools.common import Configurations
+
+__debug = None
+
+def debug():
+ global __debug
+ if __debug is None:
+ __debug = "--debug-configuration" in bjam.variable("ARGV")
+ return __debug
+
+
+# It is not yet clear what to do with Cygwin on python port.
+def on_cygwin():
+ return False
+
+
+type.register('MANIFEST', ['manifest'])
+feature.feature('embed-manifest',['on','off'], ['incidental', 'propagated']) ;
+
+type.register('PDB',['pdb'])
+
+################################################################################
+#
+# Public rules.
+#
+################################################################################
+
+# Initialize a specific toolset version configuration. As the result, path to
+# compiler and, possible, program names are set up, and will be used when that
+# version of compiler is requested. For example, you might have:
+#
+# using msvc : 6.5 : cl.exe ;
+# using msvc : 7.0 : Y:/foo/bar/cl.exe ;
+#
+# The version parameter may be ommited:
+#
+# using msvc : : Z:/foo/bar/cl.exe ;
+#
+# The following keywords have special meanings when specified as versions:
+# - all - all detected but not yet used versions will be marked as used
+# with their default options.
+# - default - this is an equivalent to an empty version.
+#
+# Depending on a supplied version, detected configurations and presence 'cl.exe'
+# in the path different results may be achieved. The following table describes
+# the possible scenarios:
+#
+# Nothing "x.y"
+# Passed Nothing "x.y" detected, detected,
+# version detected detected cl.exe in path cl.exe in path
+#
+# default Error Use "x.y" Create "default" Use "x.y"
+# all None Use all None Use all
+# x.y - Use "x.y" - Use "x.y"
+# a.b Error Error Create "a.b" Create "a.b"
+#
+# "x.y" - refers to a detected version;
+# "a.b" - refers to an undetected version.
+#
+# FIXME: Currently the command parameter and the <compiler> property parameter
+# seem to overlap in duties. Remove this duplication. This seems to be related
+# to why someone started preparing to replace init with configure rules.
+
+def init(version = None, command = None, options = None):
+ # When initialized from
+ # using msvc : x.0 ;
+ # we get version as a single element list i.e. ['x.0'],
+ # but when specified from the command line we get a string i.e. 'x.0'.
+ # We want to work with a string, so unpack the list if needed.
+ is_single_element_list = (isinstance(version,list) and len(version) == 1)
+ assert(version==None or isinstance(version,str) or is_single_element_list)
+ if is_single_element_list:
+ version = version[0]
+
+ options = to_seq(options)
+ command = to_seq(command)
+
+ if command:
+ options.append("<command>"+command)
+ configure(version,options)
+
+def configure(version=None, options=None):
+ if version == "all":
+ if options:
+ raise RuntimeError("MSVC toolset configuration: options should be empty when '{}' is specified.".format(version))
+
+ # Configure (i.e. mark as used) all registered versions.
+ all_versions = __versions.all()
+ if not all_versions:
+ if debug():
+ print "notice: [msvc-cfg] Asked to configure all registered" \
+ "msvc toolset versions when there are none currently" \
+ "registered." ;
+ else:
+ for v in all_versions:
+ # Note that there is no need to skip already configured
+ # versions here as this will request configure-really rule
+ # to configure the version using default options which will
+ # in turn cause it to simply do nothing in case the version
+ # has already been configured.
+ configure_really(v)
+ elif version == "default":
+ configure_really(None,options)
+ else:
+ configure_really(version, options)
+
+def extend_conditions(conditions,exts):
+ return [ cond + '/' + ext for cond in conditions for ext in exts ]
+
+def configure_version_specific(toolset_arg, version, conditions):
+ # Starting with versions 7.0, the msvc compiler have the /Zc:forScope and
+ # /Zc:wchar_t options that improve C++ standard conformance, but those
+ # options are off by default. If we are sure that the msvc version is at
+ # 7.*, add those options explicitly. We can be sure either if user specified
+ # version 7.* explicitly or if we auto-detected the version ourselves.
+ if not re.match('^6\\.', version):
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',conditions, ['/Zc:forScope','/Zc:wchar_t'])
+ toolset.flags('{}.compile.c++'.format(toolset_arg), 'C++FLAGS',conditions, ['/wd4675'])
+
+ # Explicitly disable the 'function is deprecated' warning. Some msvc
+ # versions have a bug, causing them to emit the deprecation warning even
+ # with /W0.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>off']), ['/wd4996'])
+ if re.match('^[78]\\.', version):
+ # 64-bit compatibility warning deprecated since 9.0, see
+ # http://msdn.microsoft.com/en-us/library/yt4xw8fh.aspx
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS',extend_conditions(conditions,['<warnings>all']), ['/Wp64'])
+
+ #
+ # Processor-specific optimization.
+ #
+ if re.match('^[67]', version ):
+ # 8.0 deprecates some of the options.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed','<optimization>space']), ['/Ogiy', '/Gs'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>speed']), ['/Ot'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<optimization>space']), ['/Os'])
+
+ cpu_arch_i386_cond = extend_conditions(conditions, __cpu_arch_i386)
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>']),['/GB'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>i386']),['/G3'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>i486']),['/G4'])
+
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g5]), ['/G5'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g6]), ['/G6'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(cpu_arch_i386_cond,['<instruction-set>' + t for t in __cpu_type_g7]), ['/G7'])
+
+ # Improve floating-point accuracy. Otherwise, some of C++ Boost's "math"
+ # tests will fail.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', conditions, ['/Op'])
+
+ # 7.1 and below have single-threaded static RTL.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>off/<runtime-link>static/<threading>single']), ['/ML'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>on/<runtime-link>static/<threading>single']), ['/MLd'])
+ else:
+ # 8.0 and above adds some more options.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' for a in __cpu_arch_amd64]), ['/favor:blend'])
+
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' + t for a in __cpu_arch_amd64 for t in __cpu_type_em64t]), ['/favor:EM64T'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions, [a + '/<instruction-set>' + t for a in __cpu_arch_amd64 for t in __cpu_type_amd64]), ['/favor:AMD64'])
+
+ # 8.0 and above only has multi-threaded static RTL.
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>off/<runtime-link>static/<threading>single']), ['/MT'])
+ toolset.flags('{}.compile'.format(toolset_arg), 'CFLAGS', extend_conditions(conditions,['<runtime-debugging>on/<runtime-link>static/<threading>single']), ['/MTd'])
+
+ # Specify target machine type so the linker will not need to guess.
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_amd64), ['/MACHINE:X64'])
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_i386), ['/MACHINE:X86'])
+ toolset.flags('{}.link'.format(toolset_arg), 'LINKFLAGS', extend_conditions(conditions, __cpu_arch_ia64), ['/MACHINE:IA64'])
+
+ # 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'])
+
+
+# Registers this toolset including all of its flags, features & generators. Does
+# nothing on repeated calls.
+
+def register_toolset():
+ if not 'msvc' in feature.values('toolset'):
+ register_toolset_really()
+
+
+engine = get_manager().engine()
+
+# 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
+#
+# Poking at source targets this way is probably not clean, but it's the
+# easiest approach.
+def archive(targets, sources=None, properties=None):
+ bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb')
+
+# Declare action for creating static libraries. If library exists, remove it
+# before adding files. See
+# http://article.gmane.org/gmane.comp.lib.boost.build/4241 for rationale.
+if not on_cygwin():
+ engine.register_action(
+ 'msvc.archive',
+ '''if exist "$(<[1])" DEL "$(<[1])"
+ $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
+ function=archive)
+else:
+ engine.register_action(
+ 'msvc.archive',
+ '''{rm} "$(<[1])"
+ $(.LD) $(AROPTIONS) /out:"$(<[1])" @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"'''.format(rm=common.rm_command()),
+ function=archive)
+
+# For the assembler the following options are turned on by default:
+#
+# -Zp4 align structures to 4 bytes
+# -Cp preserve case of user identifiers
+# -Cx preserve case in publics, externs
+#
+engine.register_action(
+ 'msvc.compile.asm',
+ '$(.ASM) -c -Zp4 -Cp -Cx -D$(DEFINES) $(ASMFLAGS) $(USER_ASMFLAGS) -Fo "$(<:W)" "$(>:W)"' )
+
+
+# Equivalent to [ on $(target) return $(prefix)$(var)$(suffix) ]. Note that $(var) can be a list.
+def expand_target_variable(target,var,prefix=None,suffix=None):
+ list = bjam.call( 'get-target-variable', target, var )
+ return " ".join([ ("" if prefix is None else prefix) + elem + ("" if suffix is None else suffix) for elem in list ])
+
+
+compile_c_cpp_pch = '''$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" "@($(<[1]:W).cpp:E=#include $(.escaped-double-quote)$(>[1]:D=)$(.escaped-double-quote)$(.nl))" $(.CC.FILTER)'''
+# Action for running the C/C++ compiler using precompiled headers. An already
+# built source file for compiling the precompiled headers is expected to be
+# given as one of the source parameters.
+compile_c_cpp_pch_s = '''$(.CC) @"@($(<[1]:W).rsp:E="$(>[2]:W)" -Fo"$(<[2]:W)" -Yc"$(>[1]:D=)" $(YLOPTION)"__bjam_pch_symbol_$(>[1]:D=)" -Fp"$(<[1]:W)" $(CC_RSPLINE))" $(.CC.FILTER)'''
+
+def get_rspline(targets, lang_opt):
+ result = lang_opt + ' ' + \
+ expand_target_variable(targets, 'UNDEFS', '-U' ) + ' ' + \
+ expand_target_variable(targets, 'CFLAGS' ) + ' ' + \
+ expand_target_variable(targets, 'C++FLAGS' ) + ' ' + \
+ expand_target_variable(targets, 'OPTIONS' ) + ' -c ' + \
+ expand_target_variable(targets, 'DEFINES', '\n-D' ) + ' ' + \
+ expand_target_variable(targets, 'INCLUDES', '\n"-I', '"' )
+ bjam.call('set-target-variable', targets, 'CC_RSPLINE', result)
+
+def compile_c(targets, sources = [], properties = None):
+ get_manager().engine().set_target_variable( targets[1], 'C++FLAGS', '' )
+ get_rspline(targets, '-TC')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ compile_c_cpp(targets,sources)
+
+def compile_c_preprocess(targets, sources = [], properties = None):
+ get_manager().engine().set_target_variable( target[1], 'C++FLAGS', '' )
+ get_rspline(targets, '-TC')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ preprocess_c_cpp(targets,sources)
+
+def compile_c_pch(targets, sources = [], properties = []):
+ get_manager().engine().set_target_variable( target[1], 'C++FLAGS', '' )
+ get_rspline([targets[1]], '-TC')
+ get_rspline([targets[2]], '-TC')
+ pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
+ sources += pch_source
+ if pch_source:
+ get_manager().engine().set_update_action('compile-c-c++-pch-s', targets, sources, properties)
+ get_manager().engine().add_dependency(targets,pch_source)
+ compile_c_cpp_pch_s(targets,sources)
+ else:
+ get_manager().engine().set_update_action('compile-c-c++-pch', targets, sources, properties)
+ compile_c_cpp_pch(targets,sources)
+
+toolset.flags( 'msvc', 'YLOPTION', [], ['-Yl'] )
+
+def compile_cpp(targets,sources=[],properties=None):
+ get_rspline(targets,'-TP')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ compile_c_cpp(targets,sources)
+
+def compile_cpp_preprocess(targets,sources=[],properties=None):
+ get_rspline(targets,'-TP')
+ sources += bjam.call('get-target-variable',targets,'PCH_FILE')
+ sources += bjam.call('get-target-variable',targets,'PCH_HEADER')
+ preprocess_c_cpp(targets,sources)
+
+def compile_cpp_pch(targets,sources=[],properties=None):
+ get_rspline([targets[1]], '-TP')
+ get_rspline([targets[2]], '-TP')
+ pch_source = bjam.call('get-target-variable', targets, 'PCH_SOURCE')
+ sources += pch_source
+ if pch_source:
+ get_manager().engine().set_update_action('compile-c-c++-pch-s', targets, sources, properties)
+ get_manager().engine().add_dependency(targets,pch_source)
+ compile_c_cpp_pch_s(targets,sources)
+ else:
+ get_manager().engine().set_update_action('compile-c-c++-pch', targets, sources, properties)
+ compile_c_cpp_pch(targets,sources)
+
+
+# Action for running the C/C++ compiler without using precompiled headers.
+#
+# 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
+#
+# 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 the compiler must be used to create a single PDB for our library.
+#
+
+compile_action = '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -Fo"$(<[1]:W)" $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" $(.CC.FILTER)'
+engine.register_action(
+ 'msvc.compile.c',
+ compile_action,
+ function=compile_c,
+ bound_list=['PDB_NAME'])
+
+engine.register_action(
+ 'msvc.compile.c++',
+ compile_action,
+ function=compile_cpp,
+ bound_list=['PDB_NAME'])
+
+
+preprocess_action = '$(.CC) @"@($(<[1]:W).rsp:E="$(>[1]:W)" -E $(PDB_CFLAG)"$(PDB_NAME)" -Yu"$(>[3]:D=)" -Fp"$(>[2]:W)" $(CC_RSPLINE))" >"$(<[1]:W)"'
+
+engine.register_action(
+ 'msvc.preprocess.c',
+ preprocess_action,
+ function=compile_c_preprocess,
+ bound_list=['PDB_NAME'])
+
+engine.register_action(
+ 'msvc.preprocess.c++',
+ preprocess_action,
+ function=compile_cpp_preprocess,
+ bound_list=['PDB_NAME'])
+
+def compile_c_cpp(targets,sources=None):
+ pch_header = bjam.call('get-target-variable',targets[0],'PCH_HEADER')
+ pch_file = bjam.call('get-target-variable',targets[0],'PCH_FILE')
+ if pch_header: get_manager().engine().add_dependency(targets[0],pch_header)
+ if pch_file: get_manager().engine().add_dependency(targets[0],pch_file)
+ bjam.call('set-target-variable',targets,'PDB_NAME', os.path.splitext(targets[0])[0] + '.pdb')
+
+def preprocess_c_cpp(targets,sources=None):
+ #same as above
+ return compile_c_cpp(targets,sources)
+
+# Action for running the C/C++ compiler using precompiled headers. In addition
+# to whatever else it needs to compile, this action also adds a temporary source
+# .cpp file used to compile the precompiled headers themselves.
+
+engine.register_action(
+ 'msvc.compile.c.pch',
+ None, # action set by the function
+ function=compile_c_pch)
+
+engine.register_action(
+ 'msvc.compile.c++.pch',
+ None, # action set by the function
+ function=compile_cpp_pch)
+
+
+# See midl.py for details.
+#
+engine.register_action(
+ 'msvc.compile.idl',
+ '''$(.IDL) /nologo @"@($(<[1]:W).rsp:E=
+"$(>:W)"
+-D$(DEFINES)
+"-I$(INCLUDES:W)"
+-U$(UNDEFS)
+$(MIDLFLAGS)
+/tlb "$(<[1]:W)"
+/h "$(<[2]:W)"
+/iid "$(<[3]:W)"
+/proxy "$(<[4]:W)"
+/dlldata "$(<[5]:W)")"
+ {touch} "$(<[4]:W)"
+ {touch} "$(<[5]:W)"'''.format(touch=common.file_creation_command()))
+
+engine.register_action(
+ 'msvc.compile.mc',
+ '$(.MC) $(MCFLAGS) -h "$(<[1]:DW)" -r "$(<[2]:DW)" "$(>:W)"')
+
+engine.register_action(
+ 'msvc.compile.rc',
+ '$(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES:W)" -fo "$(<:W)" "$(>:W)"')
+
+def link_dll(targets,sources=None,properties=None):
+ get_manager().engine().add_dependency(targets,bjam.call('get-target-variable',targets,'DEF_FILE'))
+ manifest(targets, sources, properties)
+
+def manifest(targets,sources=None,properties=None):
+ if 'on' in properties.get('<embed-manifest>'):
+ get_manager().engine().set_update_action('msvc.manifest', targets, sources, properties)
+
+
+# Incremental linking a DLL causes no end of problems: if the actual exports do
+# not change, the import .lib file is never updated. Therefore, the .lib is
+# always out-of-date and gets rebuilt every time. I am not sure that incremental
+# linking is such a great idea in general, but in this case I am sure we do not
+# want it.
+
+# Windows manifest is a new way to specify dependencies on managed DotNet
+# assemblies and Windows native DLLs. The manifests are embedded as resources
+# and are useful in any PE target (both DLL and EXE).
+
+if not on_cygwin():
+ engine.register_action(
+ 'msvc.link',
+ '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
+if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''',
+ function=manifest,
+ bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest',
+ '''if exist "$(<[1]).manifest" (
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
+ )''')
+
+ engine.register_action(
+ 'msvc.link.dll',
+ '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
+if %ERRORLEVEL% NEQ 0 EXIT %ERRORLEVEL%''',
+ function=link_dll,
+ bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest.dll',
+ '''if exist "$(<[1]).manifest" (
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
+ )''')
+else:
+ engine.register_action(
+ 'msvc.link',
+ '''$(.LD) $(LINKFLAGS) /out:"$(<[1]:W)" /LIBPATH:"$(LINKPATH:W)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
+ function=manifest,
+ bound_list=['PDB_NAME','DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest',
+ '''if test -e "$(<[1]).manifest"; then
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);1"
+ fi''')
+
+ engine.register_action(
+ 'msvc.link.dll',
+ '''$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=
+"$(>)"
+$(LIBRARIES_MENTIONED_BY_FILE)
+$(LIBRARIES)
+"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib"
+"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"''',
+ function=link_dll,
+ bound_list=['DEF_FILE','LIBRARIES_MENTIONED_BY_FILE'])
+
+ engine.register_action(
+ 'msvc.manifest.dll',
+ '''if test -e "$(<[1]).manifest"; then
+ $(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
+ fi''')
+
+
+################################################################################
+#
+# Classes.
+#
+################################################################################
+
+class MsvcPchGenerator(pch.PchGenerator):
+
+ # Inherit the __init__ method
+
+ def run_pch(self, project, name, prop_set, sources):
+ # Find the header in sources. Ignore any CPP sources.
+ pch_header = None
+ pch_source = None
+ for s in sources:
+ if type.is_derived(s.type(), 'H'):
+ pch_header = s
+ elif type.is_derived(s.type(), 'CPP') or type.is_derived(s.type(), 'C'):
+ pch_source = s
+
+ if not pch-header:
+ raise RuntimeError( "can not build pch without pch-header" )
+
+ # If we do not have the PCH source - that is fine. We will just create a
+ # temporary .cpp file in the action.
+ temp_prop_set = property_set.create([Property('pch-source',pch_source)]+prop_set.all())
+ generated = Generator.run(project,name,temp_prop_set,pch_header)
+ pch_file = None
+ for g in generated:
+ if type.is_derived(g.type(), 'PCH'):
+ pch_file = g
+ return property_set.create([Property('pch-header',pch_header),Property('pch-file',pch_file)]+generated)
+
+
+################################################################################
+#
+# Local rules.
+#
+################################################################################
+
+# Detects versions listed as '_known_versions' by checking registry information,
+# environment variables & default paths. Supports both native Windows and
+# Cygwin.
+def auto_detect_toolset_versions():
+ if on_windows() or on_cygwin():
+ for version in _known_versions:
+ versionVarName = '__version_{}_reg'.format(version.replace('.','_'))
+ if versionVarName in globals():
+ vc_path = None
+ for x in [ '', 'Wow6432Node\\' ]:
+ try:
+ with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\{}{}'.format(x, globals()[versionVarName])) as reg_key:
+ vc_path = _winreg.QueryValueEx(reg_key, "ProductDir")[0]
+ except:
+ pass
+ if vc_path:
+ vc_path = os.path.join(vc_path,'bin')
+ register_configuration(version,os.path.normpath(vc_path))
+
+ for i in _known_versions:
+ if not i in __versions.all():
+ register_configuration(i,default_path(i))
+
+
+# Worker rule for toolset version configuration. Takes an explicit version id or
+# nothing in case it should configure the default toolset version (the first
+# registered one or a new 'default' one in case no toolset versions have been
+# registered yet).
+#
+
+def configure_really(version=None, options=[]):
+ v = version
+ if not v:
+ # Take the first registered (i.e. auto-detected) version.
+ version = __versions.first()
+ v = version
+
+ # Note: 'version' can still be empty at this point if no versions have
+ # been auto-detected.
+ if not version:
+ version = "default"
+
+ # Version alias -> real version number.
+ version = globals().get("__version_alias_{}".format(version), version)
+
+ # Check whether the selected configuration is already in use.
+ if version in __versions.used():
+ # Allow multiple 'toolset.using' calls for the same configuration if the
+ # identical sets of options are used.
+ if options and options != __versions.get(version,'options'):
+ raise RuntimeError("MSVC toolset configuration: Toolset version '$(version)' already configured.".format(version))
+ else:
+ # Register a new configuration.
+ __versions.register(version)
+
+ # Add user-supplied to auto-detected options.
+ version_opts = __versions.get(version, 'options')
+ if (version_opts):
+ options = version_opts + options
+
+ # Mark the configuration as 'used'.
+ __versions.use(version)
+ # Generate conditions and save them.
+ conditions = common.check_init_parameters('msvc', None, ('version', v))
+ __versions.set(version, 'conditions', conditions)
+ command = feature.get_values('<command>', options)
+
+ # If version is specified, we try to search first in default paths, and
+ # only then in PATH.
+ command = common.get_invocation_command('msvc', 'cl.exe', command, default_paths(version))
+ common.handle_options('msvc', conditions, command, options)
+
+ if not version:
+ # Even if version is not explicitly specified, try to detect the
+ # version from the path.
+ # FIXME: We currently detect both Microsoft Visual Studio 9.0 and
+ # 9.0express as 9.0 here.
+ if re.search("Microsoft Visual Studio 11", command):
+ version = '11.0'
+ if re.search("Microsoft Visual Studio 10", command):
+ version = '10.0'
+ elif re.search("Microsoft Visual Studio 9", command):
+ version = '9.0'
+ elif re.search("Microsoft Visual Studio 8", command):
+ version = '8.0'
+ elif re.search("NET 2003[\/\\]VC7", command):
+ version = '7.1'
+ elif re.search("Microsoft Visual C\\+\\+ Toolkit 2003", command):
+ version = '7.1toolkit'
+ elif re.search(".NET[\/\\]VC7", command):
+ version = '7.0'
+ else:
+ version = '6.0'
+
+ # Generate and register setup command.
+
+ below_8_0 = re.search("^[67]\\.",version) != None
+
+ if below_8_0:
+ cpu = ['i386']
+ else:
+ cpu = ['i386', 'amd64', 'ia64']
+
+ setup_scripts = {}
+
+ if command:
+ # TODO: Note that if we specify a non-existant toolset version then
+ # this rule may find and use a corresponding compiler executable
+ # belonging to an incorrect toolset version. For example, if you
+ # have only MSVC 7.1 installed, have its executable on the path and
+ # specify you want Boost Build to use MSVC 9.0, then you want Boost
+ # Build to report an error but this may cause it to silently use the
+ # MSVC 7.1 compiler even though it thinks it is using the msvc-9.0
+ # toolset version.
+ command = common.get_absolute_tool_path(command)
+
+ if command:
+ parent = os.path.dirname(os.path.normpath(command))
+ # Setup will be used if the command name has been specified. If
+ # setup is not specified explicitly then a default setup script will
+ # be used instead. Setup scripts may be global or arhitecture/
+ # /platform/cpu specific. Setup options are used only in case of
+ # global setup scripts.
+
+ # Default setup scripts provided with different VC distributions:
+ #
+ # VC 7.1 had only the vcvars32.bat script specific to 32 bit i386
+ # builds. It was located in the bin folder for the regular version
+ # and in the root folder for the free VC 7.1 tools.
+ #
+ # Later 8.0 & 9.0 versions introduce separate platform specific
+ # vcvars*.bat scripts (e.g. 32 bit, 64 bit AMD or 64 bit Itanium)
+ # located in or under the bin folder. Most also include a global
+ # vcvarsall.bat helper script located in the root folder which runs
+ # one of the aforementioned vcvars*.bat scripts based on the options
+ # passed to it. So far only the version coming with some PlatformSDK
+ # distributions does not include this top level script but to
+ # support those we need to fall back to using the worker scripts
+ # directly in case the top level script can not be found.
+
+ global_setup = feature.get_values('<setup>',options)
+ if global_setup:
+ global_setup = global_setup[0]
+ else:
+ global_setup = None
+
+ if not below_8_0 and not global_setup:
+ global_setup = locate_default_setup(command,parent,'vcvarsall.bat')
+
+
+ default_setup = {
+ 'amd64' : 'vcvarsx86_amd64.bat',
+ 'i386' : 'vcvars32.bat',
+ 'ia64' : 'vcvarsx86_ia64.bat' }
+
+ # http://msdn2.microsoft.com/en-us/library/x4d2c09s(VS.80).aspx and
+ # http://msdn2.microsoft.com/en-us/library/x4d2c09s(vs.90).aspx
+ # mention an x86_IPF option, that seems to be a documentation bug
+ # and x86_ia64 is the correct option.
+ default_global_setup_options = {
+ 'amd64' : 'x86_amd64',
+ 'i386' : 'x86',
+ 'ia64' : 'x86_ia64' }
+
+ somehow_detect_the_itanium_platform = None
+ # When using 64-bit Windows, and targeting 64-bit, it is possible to
+ # use a native 64-bit compiler, selected by the "amd64" & "ia64"
+ # parameters to vcvarsall.bat. There are two variables we can use --
+ # PROCESSOR_ARCHITECTURE and PROCESSOR_IDENTIFIER. The first is
+ # 'x86' when running 32-bit Windows, no matter which processor is
+ # used, and 'AMD64' on 64-bit windows on x86 (either AMD64 or EM64T)
+ # Windows.
+ #
+ if re.search( 'AMD64', environ[ "PROCESSOR_ARCHITECTURE" ] ) != None:
+ default_global_setup_options[ 'amd64' ] = 'amd64'
+ # TODO: The same 'native compiler usage' should be implemented for
+ # the Itanium platform by using the "ia64" parameter. For this
+ # though we need someone with access to this platform who can find
+ # out how to correctly detect this case.
+ elif somehow_detect_the_itanium_platform:
+ default_global_setup_options[ 'ia64' ] = 'ia64'
+
+ setup_prefix = "call "
+ setup_suffix = """ >nul\n"""
+ if on_cygwin():
+ setup_prefix = "cmd.exe /S /C call "
+ setup_suffix = " \">nul\" \"&&\" "
+
+ for c in cpu:
+ setup_options = None
+ setup_cpu = feature.get_values('<setup-{}>'.format(c),options)
+
+ if not setup_cpu:
+ if global_setup:
+ setup_cpu = global_setup
+ # If needed we can easily add using configuration flags
+ # here for overriding which options get passed to the
+ # global setup command for which target platform:
+ # setup_options = feature.get_values('<setup-options-{}>'.format(c),options)
+ if not setup_options:
+ setup_options = default_global_setup_options[ c ]
+ else:
+ setup_cpu = locate_default_setup(command, parent, default_setup[ c ])
+
+ # Cygwin to Windows path translation.
+ # setup-$(c) = "\""$(setup-$(c):W)"\"" ;
+
+ # Append setup options to the setup name and add the final setup
+ # prefix & suffix.
+ setup_scripts[ c ] = '{}"{}" {}{}'.format(setup_prefix, setup_cpu, setup_options, setup_suffix)
+
+ # Get tool names (if any) and finish setup.
+ compiler = feature.get_values("<compiler>", options)
+ if not compiler:
+ compiler = "cl"
+
+ linker = feature.get_values("<linker>", options)
+ if not linker:
+ linker = "link"
+
+ resource_compiler = feature.get_values("<resource-compiler>", options)
+ if not resource_compiler:
+ resource_compiler = "rc"
+
+ # Turn on some options for i386 assembler
+ # -coff generate COFF format object file (compatible with cl.exe output)
+ default_assembler_amd64 = 'ml64'
+ default_assembler_i386 = 'ml -coff'
+ default_assembler_ia64 = 'ias'
+
+ assembler = feature.get_values('<assembler>',options)
+
+ idl_compiler = feature.get_values('<idl-compiler>',options)
+ if not idl_compiler:
+ idl_compiler = 'midl'
+
+ mc_compiler = feature.get_values('<mc-compiler>',options)
+ if not mc_compiler:
+ mc_compiler = 'mc'
+
+ manifest_tool = feature.get_values('<manifest-tool>',options)
+ if not manifest_tool:
+ manifest_tool = 'mt'
+
+ cc_filter = feature.get_values('<compiler-filter>',options)
+
+ for c in cpu:
+ cpu_conditions = [ condition + '/' + arch for arch in globals()['__cpu_arch_{}'.format(c)] for condition in conditions ]
+
+ setup_script = setup_scripts.get(c, '')
+
+ if debug():
+ for cpu_condition in cpu_conditions:
+ print "notice: [msvc-cfg] condition: '{}', setup: '{}'".format(cpu_condition,setup_script)
+
+ cpu_assembler = assembler
+ if not cpu_assembler:
+ cpu_assembler = locals()['default_assembler_{}'.format(c)]
+
+ toolset.flags('msvc.compile', '.CC' , cpu_conditions, ['{}{} /Zm800 -nologo' .format(setup_script, compiler)])
+ toolset.flags('msvc.compile', '.RC' , cpu_conditions, ['{}{} -nologo' .format(setup_script, resource_compiler)])
+ toolset.flags('msvc.compile', '.ASM', cpu_conditions, ['{}{} ' .format(setup_script, cpu_assembler)])
+ toolset.flags('msvc.link' , '.LD' , cpu_conditions, ['{}{} /NOLOGO /INCREMENTAL:NO'.format(setup_script, linker)])
+ toolset.flags('msvc.archive', '.LD' , cpu_conditions, ['{}{} /lib /NOLOGO' .format(setup_script, linker)])
+ toolset.flags('msvc.compile', '.IDL', cpu_conditions, ['{}{} ' .format(setup_script, idl_compiler)])
+ toolset.flags('msvc.compile', '.MC' , cpu_conditions, ['{}{} ' .format(setup_script, mc_compiler)])
+ toolset.flags('msvc.link' , '.MT' , cpu_conditions, ['{}{} -nologo' .format(setup_script, manifest_tool)])
+
+ if cc_filter:
+ toolset.flags('msvc', '.CC.FILTER', cpu_conditions, ['"|" {}'.format(cc_filter)])
+
+ # Set version-specific flags.
+ configure_version_specific('msvc', version, conditions)
+
+
+# Returns the default installation path for the given version.
+#
+def default_path(version):
+ # Use auto-detected path if possible.
+ options = __versions.get(version, 'options')
+ tmp_path = None
+ if options:
+ tmp_path = feature.get_values('<command>', options)
+
+ if tmp_path:
+ tmp_path="".join(tmp_path)
+ tmp_path=os.path.dirname(tmp_path)
+ else:
+ env_var_var_name = '__version_{}_env'.format(version.replace('.','_'))
+ vc_path = None
+ if env_var_var_name in globals():
+ env_var_name = globals()[env_var_var_name]
+ if env_var_name in os.environ:
+ vc_path = environ[env_var_name]
+ if vc_path:
+ vc_path = os.path.join(vc_path,globals()['__version_{}_envpath'.format(version.replace('.','_'))])
+ tmp_path = os.path.normpath(vc_path)
+
+ var_name = '__version_{}_path'.format(version.replace('.','_'))
+ if not tmp_path and var_name in globals():
+ tmp_path = os.path.normpath(os.path.join(common.get_program_files_dir(), globals()[var_name]))
+ return tmp_path
+
+
+# Returns either the default installation path (if 'version' is not empty) or
+# list of all known default paths (if no version is given)
+#
+def default_paths(version = None):
+ possible_paths = []
+ if version:
+ path = default_path(version)
+ if path:
+ possible_paths.append(path)
+ else:
+ for i in _known_versions:
+ path = default_path(i)
+ if path:
+ possible_paths.append(path)
+ return possible_paths
+
+
+class MsvcLinkingGenerator(builtin.LinkingGenerator):
+ # Calls the base version. If necessary, also create a target for the
+ # manifest file.specifying source's name as the name of the created
+ # target. As result, the PCH will be named whatever.hpp.gch, and not
+ # whatever.gch.
+ def generated_targets(self, sources, prop_set, project, name):
+ result = builtin.LinkingGenerator.generated_targets(self, sources, prop_set, project, name)
+ if result:
+ name_main = result[0].name()
+ action = result[0].action()
+
+ if prop_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.
+ target = FileTarget(name_main.split_ext()[0]+'.pdb','PDB',project,action,True)
+ registered_target = virtual_target.register(target)
+ if target != registered_target:
+ action.replace_targets(target,registered_target)
+ result.append(registered_target)
+ if prop_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.
+ target = FileTarget(name_main+'.manifest', 'MANIFEST', project, action, True)
+ registered_target = virtual_target.register(target)
+ if target != registered_target:
+ action.replace_targets(target,registered_target)
+ result.append(registered_target)
+ return result
+
+
+# Unsafe worker rule for the register-toolset() rule. Must not be called
+# multiple times.
+
+def register_toolset_really():
+ feature.extend('toolset', ['msvc'])
+
+ # Intel and msvc supposedly have link-compatible objects.
+ feature.subfeature( 'toolset', 'msvc', 'vendor', 'intel', ['propagated', 'optional'])
+
+ # Inherit MIDL flags.
+ toolset.inherit_flags('msvc', 'midl')
+
+ # Inherit MC flags.
+ toolset.inherit_flags('msvc','mc')
+
+ # Dynamic runtime comes only in MT flavour.
+ toolset.add_requirements(['<toolset>msvc,<runtime-link>shared:<threading>multi'])
+
+ # Declare msvc toolset specific features.
+ feature.feature('debug-store', ['object', 'database'], ['propagated'])
+ feature.feature('pch-source', [], ['dependency', 'free'])
+
+ # Declare generators.
+
+ # 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(MsvcLinkingGenerator('msvc.link', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['EXE'], ['<toolset>msvc']))
+ generators.register(MsvcLinkingGenerator('msvc.link.dll', True, ['OBJ', 'SEARCHED_LIB', 'STATIC_LIB', 'IMPORT_LIB'], ['SHARED_LIB','IMPORT_LIB'], ['<toolset>msvc']))
+
+ builtin.register_archiver('msvc.archive', ['OBJ'], ['STATIC_LIB'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c++', ['CPP'], ['OBJ'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c', ['C'], ['OBJ'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c++.preprocess', ['CPP'], ['PREPROCESSED_CPP'], ['<toolset>msvc'])
+ builtin.register_c_compiler('msvc.compile.c.preprocess', ['C'], ['PREPROCESSED_C'], ['<toolset>msvc'])
+
+ # Using 'register-c-compiler' adds the build directory to INCLUDES.
+ builtin.register_c_compiler('msvc.compile.rc', ['RC'], ['OBJ(%_res)'], ['<toolset>msvc'])
+ generators.override('msvc.compile.rc', 'rc.compile.resource')
+ generators.register_standard('msvc.compile.asm', ['ASM'], ['OBJ'], ['<toolset>msvc'])
+
+ builtin.register_c_compiler('msvc.compile.idl', ['IDL'], ['MSTYPELIB', 'H', 'C(%_i)', 'C(%_proxy)', 'C(%_dlldata)'], ['<toolset>msvc'])
+ generators.override('msvc.compile.idl', 'midl.compile.idl')
+
+ generators.register_standard('msvc.compile.mc', ['MC'], ['H','RC'], ['<toolset>msvc'])
+ generators.override('msvc.compile.mc', 'mc.compile')
+
+ # Note: the 'H' source type will catch both '.h' and '.hpp' headers as
+ # the latter have their HPP type derived from H. The type of compilation
+ # is determined entirely by the destination type.
+ generators.register(MsvcPchGenerator('msvc.compile.c.pch', False, ['H'], ['C_PCH','OBJ'], ['<pch>on', '<toolset>msvc']))
+ generators.register(MsvcPchGenerator('msvc.compile.c++.pch', False, ['H'], ['CPP_PCH','OBJ'], ['<pch>on', '<toolset>msvc']))
+
+ generators.override('msvc.compile.c.pch', 'pch.default-c-pch-generator')
+ generators.override('msvc.compile.c++.pch', 'pch.default-cpp-pch-generator')
+
+ toolset.flags('msvc.compile', 'PCH_FILE' , ['<pch>on'], ['<pch-file>' ])
+ toolset.flags('msvc.compile', 'PCH_SOURCE', ['<pch>on'], ['<pch-source>'])
+ toolset.flags('msvc.compile', 'PCH_HEADER', ['<pch>on'], ['<pch-header>'])
+
+ #
+ # Declare flags for compilation.
+ #
+ toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>speed'], ['/O2'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>space'], ['/O1'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', [ a + '/<instruction-set>' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium ], ['/G1'])
+ toolset.flags('msvc.compile', 'CFLAGS', [ a + '/<instruction-set>' + t for a in __cpu_arch_ia64 for t in __cpu_type_itanium2 ], ['/G2'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', ['<debug-symbols>on/<debug-store>object'], ['/Z7'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<debug-symbols>on/<debug-store>database'], ['/Zi'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<optimization>off'], ['/Od'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>off'], ['/Ob0'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>on'], ['/Ob1'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<inlining>full'], ['/Ob2'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>on'], ['/W3'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>off'], ['/W0'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings>all'], ['/W4'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<warnings-as-errors>on'], ['/WX'])
+
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>off'], ['/EHs'])
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>off/<extern-c-nothrow>on'], ['/EHsc'])
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>off'], ['/EHa'])
+ toolset.flags('msvc.compile', 'C++FLAGS', ['<exception-handling>on/<asynch-exceptions>on/<extern-c-nothrow>on'], ['/EHac'])
+
+ # By default 8.0 enables rtti support while prior versions disabled it. We
+ # simply enable or disable it explicitly so we do not have to depend on this
+ # default behaviour.
+ toolset.flags('msvc.compile', 'CFLAGS', ['<rtti>on'], ['/GR'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<rtti>off'], ['/GR-'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>off/<runtime-link>shared'], ['/MD'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>on/<runtime-link>shared'], ['/MDd'])
+
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>off/<runtime-link>static/<threading>multi'], ['/MT'])
+ toolset.flags('msvc.compile', 'CFLAGS', ['<runtime-debugging>on/<runtime-link>static/<threading>multi'], ['/MTd'])
+
+ toolset.flags('msvc.compile', 'OPTIONS', [], ['<cflags>'])
+ toolset.flags('msvc.compile.c++', 'OPTIONS', [], ['<cxxflags>'])
+
+ toolset.flags('msvc.compile', 'PDB_CFLAG', ['<debug-symbols>on/<debug-store>database'],['/Fd'])
+
+ toolset.flags('msvc.compile', 'DEFINES', [], ['<define>'])
+ toolset.flags('msvc.compile', 'UNDEFS', [], ['<undef>'])
+ toolset.flags('msvc.compile', 'INCLUDES', [], ['<include>'])
+
+ # Declare flags for the assembler.
+ toolset.flags('msvc.compile.asm', 'USER_ASMFLAGS', [], ['<asmflags>'])
+
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<debug-symbols>on'], ['/Zi', '/Zd'])
+
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>on'], ['/W3'])
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>off'], ['/W0'])
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings>all'], ['/W4'])
+ toolset.flags('msvc.compile.asm', 'ASMFLAGS', ['<warnings-as-errors>on'], ['/WX'])
+
+ toolset.flags('msvc.compile.asm', 'DEFINES', [], ['<define>'])
+
+ # Declare flags for linking.
+ toolset.flags('msvc.link', 'PDB_LINKFLAG', ['<debug-symbols>on/<debug-store>database'], ['/PDB']) # not used yet
+ toolset.flags('msvc.link', 'LINKFLAGS', ['<debug-symbols>on'], ['/DEBUG'])
+ toolset.flags('msvc.link', 'DEF_FILE', [], ['<def-file>'])
+
+ # The linker disables the default optimizations when using /DEBUG so we
+ # have to enable them manually for release builds with debug symbols.
+ toolset.flags('msvc', 'LINKFLAGS', ['<debug-symbols>on/<runtime-debugging>off'], ['/OPT:REF,ICF'])
+
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>console'], ['/subsystem:console'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>gui'], ['/subsystem:windows'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>wince'], ['/subsystem:windowsce'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>native'], ['/subsystem:native'])
+ toolset.flags('msvc', 'LINKFLAGS', ['<user-interface>auto'], ['/subsystem:posix'])
+
+ toolset.flags('msvc.link', 'OPTIONS', [], ['<linkflags>'])
+ toolset.flags('msvc.link', 'LINKPATH', [], ['<library-path>'])
+
+ toolset.flags('msvc.link', 'FINDLIBS_ST', ['<find-static-library>'])
+ toolset.flags('msvc.link', 'FINDLIBS_SA', ['<find-shared-library>'])
+ toolset.flags('msvc.link', 'LIBRARY_OPTION', ['<toolset>msvc'])
+ toolset.flags('msvc.link', 'LIBRARIES_MENTIONED_BY_FILE', ['<library-file>'])
+
+ toolset.flags('msvc.archive', 'AROPTIONS', [], ['<archiveflags>'])
+
+
+# Locates the requested setup script under the given folder and returns its full
+# path or nothing in case the script can not be found. In case multiple scripts
+# are found only the first one is returned.
+#
+# TODO: There used to exist a code comment for the msvc.init rule stating that
+# we do not correctly detect the location of the vcvars32.bat setup script for
+# the free VC7.1 tools in case user explicitly provides a path. This should be
+# tested or simply remove this whole comment in case this toolset version is no
+# longer important.
+#
+def locate_default_setup(command, parent, setup_name):
+ for setup in [os.path.join(dir,setup_name) for dir in [command,parent]]:
+ if os.path.exists(setup):
+ return setup
+ return None
+
+
+# Validates given path, registers found configuration and prints debug
+# information about it.
+#
+def register_configuration(version, path=None):
+ if path:
+ command = os.path.join(path, 'cl.exe')
+ if os.path.exists(command):
+ if debug():
+ print "notice: [msvc-cfg] msvc-$(version) detected, command: ''".format(version,command)
+ __versions.register(version)
+ __versions.set(version,'options',['<command>{}'.format(command)])
+
+
+################################################################################
+#
+# Startup code executed when loading this module.
+#
+################################################################################
+
+# Similar to Configurations, but remembers the first registered configuration.
+class MSVCConfigurations(Configurations):
+ def __init__(self):
+ Configurations.__init__(self)
+ self.first_ = None
+
+ def register(self, id):
+ Configurations.register(self,id)
+ if not self.first_:
+ self.first_ = id
+
+ def first(self):
+ return self.first_
+
+
+# List of all registered configurations.
+__versions = MSVCConfigurations()
+
+# Supported CPU architectures.
+__cpu_arch_i386 = [
+ '<architecture>/<address-model>',
+ '<architecture>/<address-model>32',
+ '<architecture>x86/<address-model>',
+ '<architecture>x86/<address-model>32']
+
+__cpu_arch_amd64 = [
+ '<architecture>/<address-model>64',
+ '<architecture>x86/<address-model>64']
+
+__cpu_arch_ia64 = [
+ '<architecture>ia64/<address-model>',
+ '<architecture>ia64/<address-model>64']
+
+
+# Supported CPU types (only Itanium optimization options are supported from
+# VC++ 2005 on). See
+# http://msdn2.microsoft.com/en-us/library/h66s5s0e(vs.90).aspx for more
+# detailed information.
+__cpu_type_g5 = ['i586', 'pentium', 'pentium-mmx' ]
+__cpu_type_g6 = ['i686', 'pentiumpro', 'pentium2', 'pentium3', 'pentium3m', 'pentium-m', 'k6',
+ 'k6-2', 'k6-3', 'winchip-c6', 'winchip2', 'c3', 'c3-2' ]
+__cpu_type_em64t = ['prescott', 'nocona', 'conroe', 'conroe-xe', 'conroe-l', 'allendale', 'mermon',
+ 'mermon-xe', 'kentsfield', 'kentsfield-xe', 'penryn', 'wolfdale',
+ 'yorksfield', 'nehalem' ]
+__cpu_type_amd64 = ['k8', 'opteron', 'athlon64', 'athlon-fx']
+__cpu_type_g7 = ['pentium4', 'pentium4m', 'athlon', 'athlon-tbird', 'athlon-4', 'athlon-xp'
+ 'athlon-mp'] + __cpu_type_em64t + __cpu_type_amd64
+__cpu_type_itanium = ['itanium', 'itanium1', 'merced']
+__cpu_type_itanium2 = ['itanium2', 'mckinley']
+
+
+# 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']
+
+# Version aliases.
+__version_alias_6 = '6.0'
+__version_alias_6_5 = '6.0'
+__version_alias_7 = '7.0'
+__version_alias_8 = '8.0'
+__version_alias_9 = '9.0'
+__version_alias_10 = '10.0'
+__version_alias_11 = '11.0'
+
+# Names of registry keys containing the Visual C++ installation path (relative
+# to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft").
+__version_6_0_reg = "VisualStudio\\6.0\\Setup\\Microsoft Visual C++"
+__version_7_0_reg = "VisualStudio\\7.0\\Setup\\VC"
+__version_7_1_reg = "VisualStudio\\7.1\\Setup\\VC"
+__version_8_0_reg = "VisualStudio\\8.0\\Setup\\VC"
+__version_8_0express_reg = "VCExpress\\8.0\\Setup\\VC"
+__version_9_0_reg = "VisualStudio\\9.0\\Setup\\VC"
+__version_9_0express_reg = "VCExpress\\9.0\\Setup\\VC"
+__version_10_0_reg = "VisualStudio\\10.0\\Setup\\VC"
+__version_10_0express_reg = "VCExpress\\10.0\\Setup\\VC"
+__version_11_0_reg = "VisualStudio\\11.0\\Setup\\VC"
+
+# Visual C++ Toolkit 2003 does not store its installation path in the registry.
+# The environment variable 'VCToolkitInstallDir' and the default installation
+# path will be checked instead.
+__version_7_1toolkit_path = 'Microsoft Visual C++ Toolkit 2003\\bin'
+__version_7_1toolkit_env = 'VCToolkitInstallDir'
+
+# Path to the folder containing "cl.exe" relative to the value of the
+# corresponding environment variable.
+__version_7_1toolkit_envpath = 'bin' ;
+#
+#
+# Auto-detect all the available msvc installations on the system.
+auto_detect_toolset_versions()
+
+# And finally trigger the actual Boost Build toolset registration.
+register_toolset()
diff --git a/tools/build/v2/tools/pch.py b/tools/build/v2/tools/pch.py
index 21d3db09df..71cb7166eb 100644
--- a/tools/build/v2/tools/pch.py
+++ b/tools/build/v2/tools/pch.py
@@ -29,6 +29,7 @@
# ;
from b2.build import type, feature, generators
+from b2.tools import builtin
type.register('PCH', ['pch'])
type.register('C_PCH', [], 'PCH')
@@ -48,7 +49,7 @@ class PchGenerator(generators.Generator):
from being run unless it's being used for a top-level PCH target.
"""
def action_class(self):
- return 'compile-action'
+ return builtin.CompileAction
def run(self, project, name, prop_set, sources):
if not name:
@@ -65,7 +66,7 @@ class PchGenerator(generators.Generator):
pass
else:
r = self.run_pch(project, name,
- prop_set.add_raw('<define>BOOST_BUILD_PCH_ENABLED'),
+ prop_set.add_raw(['<define>BOOST_BUILD_PCH_ENABLED']),
sources)
return generators.add_usage_requirements(
r, ['<define>BOOST_BUILD_PCH_ENABLED'])
@@ -74,10 +75,9 @@ class PchGenerator(generators.Generator):
def run_pch(self, project, name, prop_set, sources):
pass
-#FIXME: dummy-generator in builtins.jam needs to be ported.
# NOTE: requirements are empty, default pch generator can be applied when
# pch=off.
-###generators.register(
-### [ new dummy-generator pch.default-c-pch-generator : : C_PCH ] ;
-###generators.register
-### [ new dummy-generator pch.default-cpp-pch-generator : : CPP_PCH ] ;
+generators.register(builtin.DummyGenerator(
+ "pch.default-c-pch-generator", False, [], ['C_PCH'], []))
+generators.register(builtin.DummyGenerator(
+ "pch.default-cpp-pch-generator", False, [], ['CPP_PCH'], []))
diff --git a/tools/build/v2/tools/python.jam b/tools/build/v2/tools/python.jam
index 66f2aabec3..6c2073b788 100644
--- a/tools/build/v2/tools/python.jam
+++ b/tools/build/v2/tools/python.jam
@@ -1178,7 +1178,7 @@ class python-test-generator : generator
property-set = [ $(property-set).add-raw <dependency>$(other-pythons) ] ;
- result = [ construct-result $(python) $(extensions) $(new-sources) :
+ return [ construct-result $(python) $(extensions) $(new-sources) :
$(project) $(name) : $(property-set) ] ;
}
}
diff --git a/tools/build/v2/tools/stage.jam b/tools/build/v2/tools/stage.jam
index 296e7558e4..36427447bf 100644
--- a/tools/build/v2/tools/stage.jam
+++ b/tools/build/v2/tools/stage.jam
@@ -263,7 +263,7 @@ class install-target-class : basic-target
}
}
DELETE_MODULE $(result) ;
- result = [ sequence.unique $(result2) ] ;
+ return [ sequence.unique $(result2) ] ;
}
# Returns true iff 'type' is subtype of some element of 'types-to-include'.
diff --git a/tools/build/v2/tools/stage.py b/tools/build/v2/tools/stage.py
index 25eccbe513..90d3c0f976 100644
--- a/tools/build/v2/tools/stage.py
+++ b/tools/build/v2/tools/stage.py
@@ -224,7 +224,7 @@ def symlink(name, project, source, ps):
return virtual_target.FileTarget(name, source.type(), project, a, exact=True)
def relink_file(project, source, ps):
- action = source.action()
+ action = source[0].action()
cloned_action = virtual_target.clone_action(action, project, "", ps)
targets = cloned_action.targets()
# We relink only on Unix, where exe or shared lib is always a single file.
diff --git a/tools/build/v2/tools/types/__init__.py b/tools/build/v2/tools/types/__init__.py
index f972b71495..9ee31d13a3 100644
--- a/tools/build/v2/tools/types/__init__.py
+++ b/tools/build/v2/tools/types/__init__.py
@@ -5,6 +5,7 @@ __all__ = [
'html',
'lib',
'obj',
+ 'preprocessed',
'rsp',
]
diff --git a/tools/build/v2/tools/types/cpp.py b/tools/build/v2/tools/types/cpp.py
index 7b56111c85..a6703255c6 100644
--- a/tools/build/v2/tools/types/cpp.py
+++ b/tools/build/v2/tools/types/cpp.py
@@ -5,6 +5,9 @@
from b2.build import type
def register ():
- type.register_type ('CPP', ['cpp', 'cxx', 'cc'])
+ type.register_type('CPP', ['cpp', 'cxx', 'cc'])
+ type.register_type('H', ['h'])
+ type.register_type('HPP', ['hpp'], 'H')
+ type.register_type('C', ['c'])
register ()
diff --git a/tools/build/v2/tools/types/preprocessed.py b/tools/build/v2/tools/types/preprocessed.py
new file mode 100644
index 0000000000..f591043347
--- /dev/null
+++ b/tools/build/v2/tools/types/preprocessed.py
@@ -0,0 +1,11 @@
+# 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)
+
+from b2.build import type
+
+def register ():
+ type.register_type('PREPROCESSED_C', ['i'], 'C')
+ type.register_type('PREPROCESSED_CPP', ['ii'], 'CPP')
+
+register ()
diff --git a/tools/build/v2/tools/unix.py b/tools/build/v2/tools/unix.py
index d409c2e460..34758f57b5 100644
--- a/tools/build/v2/tools/unix.py
+++ b/tools/build/v2/tools/unix.py
@@ -58,8 +58,8 @@ class UnixSearchedLibGenerator (builtin.SearchedLibGenerator):
def optional_properties (self):
return self.requirements ()
- def run (self, project, name, prop_set, sources, multiple):
- result = SearchedLibGenerator.run (project, name, prop_set, sources, multiple)
+ def run (self, project, name, prop_set, sources):
+ result = SearchedLibGenerator.run (project, name, prop_set, sources)
set_library_order (sources, prop_set, result)
@@ -69,10 +69,10 @@ class UnixPrebuiltLibGenerator (generators.Generator):
def __init__ (self, id, composing, source_types, target_types_and_names, requirements):
generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements)
- def run (self, project, name, prop_set, sources, multiple):
+ def run (self, project, name, prop_set, sources):
f = prop_set.get ('<file>')
set_library_order_aux (f, sources)
- return (f, sources)
+ return f + sources
### # The derived toolset must specify their own rules and actions.
# FIXME: restore?
diff --git a/tools/build/v2/util/doc.jam b/tools/build/v2/util/doc.jam
index a751558821..6e89d075ee 100644
--- a/tools/build/v2/util/doc.jam
+++ b/tools/build/v2/util/doc.jam
@@ -670,7 +670,7 @@ local rule extract-syntax (
while ! $(syntax) && ! [ MATCH "^[$(ws)]*(#)" : $(line) ] && $($(var))
{
local m = [ MATCH "^[$(ws)]*(.*)$" : $(line) ] ;
- if $(m) && ! $(m) = ""
+ if $(m)
{
syntax = $(m) ;
}