From 4739ef1dd647e6313291bffd3fa26d6d72716760 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 14 Jul 2010 10:46:30 +0000 Subject: [PATCH 001/165] Stop 'import toolset in Jamfiles from reloading b2.build.tooset. [SVN r64011] --- v2/build/project.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 0de927acd..2d2a83074 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -585,29 +585,35 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) return result def load_module(self, name, extra_path=None): - """Classic Boost.Build 'modules' are in fact global variables. - Therefore, try to find an already loaded Python module called 'name' in sys.modules. - If the module ist not loaded, find it Boost.Build search - path and load it. The new module is not entered in sys.modules. - The motivation here is to have disjoint namespace of modules - loaded via 'import/using' in Jamfile, and ordinary Python - modules. We don't want 'using foo' in Jamfile to load ordinary - Python module 'foo' which is going to not work. And we - also don't want 'import foo' in regular Python module to - accidentally grab module named foo that is internal to - Boost.Build and intended to provide interface to Jamfiles.""" + """Load a Python module that should be useable from Jamfiles. + There are generally two types of modules Jamfiles might want to + use: + - Core Boost.Build. Those are imported using plain names, e.g. + 'toolset', so this function checks if we have module named + b2.package.module already. + - Python modules in the same directory as Jamfile. We don't + want to even temporary add Jamfile's directory to sys.path, + since then we might get naming conflicts between standard + Python modules and those. + """ + + # See if we loaded module of this name already existing = self.loaded_tool_modules_.get(name) if existing: return existing + # See if we have a module b2.whatever., where + # is what is passed to this function modules = sys.modules for class_name in modules: - if name is class_name: + parts = class_name.split('.') + if name is class_name or parts[0] == "b2" and parts[-1] == name: module = modules[class_name] self.loaded_tool_modules_[name] = module return module - + + # Lookup a module in BOOST_BUILD_PATH path = extra_path if not path: path = [] @@ -907,14 +913,14 @@ attribute is allowed only for top-level 'project' invocations""") Project global constants are normal variables but should not be changed. They are applied to every child Jamfile.""" m = "Jamfile" - self.registry.current().add_constant(name[0], value) + self.registry.current().add_constant(name[0], value[0]) def path_constant(self, name, value): """Declare and set a project global constant, whose value is a path. The path is adjusted to be relative to the invocation directory. The given value path is taken to be either absolute, or relative to this project root.""" - self.registry.current().add_constant(name[0], value, path=1) + self.registry.current().add_constant(name[0], value[0], path=1) def use_project(self, id, where): # See comment in 'load' for explanation why we record the From 89d0f7665c4cd48090de5b3141bb596d03bd030c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 16 Jul 2010 09:48:38 +0000 Subject: [PATCH 002/165] Ubreak computation of main target requirements. [SVN r64068] --- v2/build/targets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/build/targets.py b/v2/build/targets.py index 8d41ca352..2bcf8f1d0 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -146,7 +146,7 @@ class TargetRegistry: requirements = property_set.refine_from_user_input( project.get("requirements"), specification, - project.project_module, project.get("location")) + project.project_module(), project.get("location")) return requirements From ef76367a1bd2a84d805c1da1041d65506a5a5d00 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 16 Jul 2010 09:51:37 +0000 Subject: [PATCH 003/165] Update 'make' port [SVN r64070] --- v2/tools/make.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/v2/tools/make.py b/v2/tools/make.py index 18dae4894..97fa81283 100644 --- a/v2/tools/make.py +++ b/v2/tools/make.py @@ -1,4 +1,5 @@ -# Status: being ported by Vladimir Prus +# Status: ported. +# Base revision: 64068 # Copyright 2003 Dave Abrahams # Copyright 2003 Douglas Gregor @@ -20,9 +21,10 @@ class MakeTarget(BasicTarget): def construct(self, name, source_targets, property_set): action_name = property_set.get("")[0] + assert action_name[0] == '@' + action_name = action_name[1:] action = Action(get_manager(), source_targets, action_name, property_set) - # FIXME: type.type uses global data. target = FileTarget(self.name(), 1, type.type(self.name()), self.project(), action) return [ b2.build.property_set.empty(), From f41e6c5156351fe34a7a463d3ae3df894dd37c40 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 16 Jul 2010 12:09:41 +0000 Subject: [PATCH 004/165] Raise Exception, not string (which is not allowed in modern Python) [SVN r64072] --- v2/build/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/build/engine.py b/v2/build/engine.py index 246420fb4..fb4f373d0 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -144,7 +144,7 @@ class Engine: def do_set_update_action (self, action_name, targets, sources, property_set): action = self.actions.get(action_name) if not action: - raise "No action %s was registered" % action_name + raise Exception("No action %s was registered" % action_name) action(targets, sources, property_set) def do_set_target_variable (self, target, variable, value, append): From 91d3959f71d8f1037a4908a15f932e2a674986e2 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 16 Jul 2010 12:36:17 +0000 Subject: [PATCH 005/165] Update port of property.py [SVN r64073] --- v2/build/property.py | 71 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/v2/build/property.py b/v2/build/property.py index 330b8c113..490815ea6 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -1,5 +1,5 @@ # Status: ported, except for tests and --abbreviate-paths. -# Base revision: 40480 +# Base revision: 64070 # # Copyright 2001, 2002, 2003 Dave Abrahams # Copyright 2006 Rene Rivera @@ -11,6 +11,7 @@ import re from b2.util.utility import * from b2.build import feature from b2.util import sequence, set +from b2.manager import get_manager __re_two_ampersands = re.compile ('&&') __re_comma = re.compile (',') @@ -21,6 +22,7 @@ __re_split_conditional = re.compile (r'(.+):<(.+)') __re_colon = re.compile (':') __re_has_condition = re.compile (r':<') __re_separate_condition_and_property = re.compile (r'(.*):(<.*)') +__re_indirect_rule = re.compile("^([^%]*)%([^%]+)$") def reset (): """ Clear the module state. This is mainly for testing purposes. @@ -176,20 +178,32 @@ def translate_indirect(specification, context_module): either local to the module or global. Qualified local rules with the name of the module.""" result = [] - for p in specification: + for px in specification: + p = get_value(px) if p[0] == '@': + v = None m = p[1:] - if not '.' in p: - # This is unqualified rule name. The user might want - # to set flags on this rule name, and toolset.flag - # auto-qualifies the rule name. Need to do the same - # here so set flag setting work. - # We can arrange for toolset.flag to *not* auto-qualify - # the argument, but then two rules defined in two Jamfiles - # will conflict. - m = context_module + "." + m + if __re_indirect_rule.match(m): + # Rule is already in indirect format + # FIXME: it's not clear if this is necessary. + v = m + else: - result.append(get_grist(p) + "@" + m) + if not '.' in p: + # This is unqualified rule name. The user might want + # to set flags on this rule name, and toolset.flag + # auto-qualifies the rule name. Need to do the same + # here so set flag setting work. + # We can arrange for toolset.flag to *not* auto-qualify + # the argument, but then two rules defined in two Jamfiles + # will conflict. + m = context_module + "." + m + + v = m + #v = indirect.make(m, context_module) + get_manager().engine().register_bjam_action(v) + + result.append(get_grist(px) + "@" + m) else: result.append(p) @@ -241,8 +255,7 @@ def expand_subfeatures_in_conditions (properties): result.append (p) else: - individual_subfeatures = Set.difference (e, condition) - result.append (','.join (individual_subfeatures) + ':' + value) + result.append (','.join(e) + ':' + value) return result @@ -470,6 +483,36 @@ def take(attributes, properties): result.append(e) return result +def translate_dependencies(specification, project_id, location): + + result = [] + for p in specification: + split = split_conditional(p) + condition = "" + if split: + condition = split[0] + p = split[1] + + f = get_grist(p) + v = get_value(p) + if "dependency" in feature.attributes(f): + m = re.match("(.*)//(.*)", v) + if m: + rooted = m.group(1) + if rooted[0] == '/': + # Either project id or absolute Linux path, do nothing. + pass + else: + rooted = os.path.join(os.getcwd(), location, rooted[0]) + result.append(condition + f + rooted + "//" + m.group(2)) + elif os.path.isabs(m.group(v)): + result.append(condition + p) + else: + result.append(condition + f + project_id + "//" + v) + else: + result.append(condition + p) + + return result class PropertyMap: """ Class which maintains a property set -> string mapping. From 5705bdd9acfc88c136f9418a8c75b9387e31d0ac Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 07:16:18 +0000 Subject: [PATCH 006/165] Declare the feature used in the example. [SVN r64149] --- v2/example/make/jamroot.jam | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/v2/example/make/jamroot.jam b/v2/example/make/jamroot.jam index 3759e7834..7bb98e353 100644 --- a/v2/example/make/jamroot.jam +++ b/v2/example/make/jamroot.jam @@ -1,9 +1,12 @@ +import feature ; import toolset ; path-constant HERE : . ; make main.cpp : main_cpp.pro : @do-something ; -toolset.flags do-something PYTHON : ; +feature.feature example.python.interpreter : : free ; + +toolset.flags do-something PYTHON : ; actions do-something { "$(PYTHON:E=python)" "$(HERE)/foo.py" "$(>)" "$(<)" From e02ecc2e251654dcadfe40ebd5ce991b0951b655 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 08:58:05 +0000 Subject: [PATCH 007/165] Fix memory leak. Apparently, PyList_Append does not steal reference, after all. [SVN r64151] --- v2/engine/src/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/engine/src/compile.c b/v2/engine/src/compile.c index 6cc6970fa..02f508bd6 100644 --- a/v2/engine/src/compile.c +++ b/v2/engine/src/compile.c @@ -776,8 +776,8 @@ call_python_function(RULE* r, FRAME* frame) for ( ; l; l = l->next ) { PyObject * v = PyString_FromString(l->string); - /* Steals reference to 'v' */ PyList_Append( arg, v ); + Py_DECREF(v); } /* Steals reference to 'arg' */ PyTuple_SetItem( arguments, i, arg ); From 1dcece565f0b971a40bf277d6911473afe8a1657 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 13:20:51 +0000 Subject: [PATCH 008/165] Implemented a mechanism for parameter translation from bjam to python signatures. This allows to expose the same interface to Jamfiles as before, e.g. rule toolset.flags ( rule variable condition * : values * ) and use natural interface in the Python side, where, 'rule', 'variable', 'condition' and 'values' are parameters, and the first two of them will get string, not list of strings. [SVN r64158] --- v2/build/feature.py | 3 +- v2/build/project.py | 6 ++-- v2/build/toolset.py | 6 ++-- v2/engine/src/builtins.c | 28 +++++++++++++++++-- v2/engine/src/compile.c | 59 +++++++++++++++++++++++++++++++--------- v2/engine/src/lists.c | 34 +++++++++++++++++++++++ v2/engine/src/lists.h | 11 ++++++++ v2/engine/src/rules.c | 1 + v2/engine/src/rules.h | 1 + v2/util/__init__.py | 8 ++++++ 10 files changed, 136 insertions(+), 21 deletions(-) diff --git a/v2/build/feature.py b/v2/build/feature.py index 33a054478..061bb178d 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -14,7 +14,7 @@ import re -from b2.util import set, utility +from b2.util import set, utility, bjam_signature from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, to_seq from b2.exceptions import * @@ -83,6 +83,7 @@ def enumerate (): # FIXME: prepare-test/finish-test? +@bjam_signature((["name"], ["values", "*"], ["attributes", "*"])) def feature (name, values, attributes = []): """ Declares a new feature with the given name, values, and attributes. name: the feature name diff --git a/v2/build/project.py b/v2/build/project.py index 2d2a83074..0f42e500a 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -978,7 +978,6 @@ attribute is allowed only for top-level 'project' invocations""") "Tool module '%s' does not define the 'init' method" % toolset[0]) m.init(*args) - def import_(self, name, names_to_import=None, local_names=None): name = name[0] @@ -991,7 +990,10 @@ attribute is allowed only for top-level 'project' invocations""") for f in m.__dict__: v = m.__dict__[f] if callable(v): - bjam.import_rule(jamfile_module, name + "." + f, v) + if hasattr(v, "bjam_signature"): + bjam.import_rule(jamfile_module, name + "." + f, v, v.bjam_signature) + else: + bjam.import_rule(jamfile_module, name + "." + f, v) if names_to_import: if not local_names: diff --git a/v2/build/toolset.py b/v2/build/toolset.py index af2486a5a..f952c3f6a 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -12,7 +12,7 @@ import feature, property, generators, property_set from b2.util.utility import * -from b2.util import set +from b2.util import set, bjam_signature __re_split_last_segment = re.compile (r'^(.+)\.([^\.])*') __re_two_ampersands = re.compile ('(&&)') @@ -87,7 +87,9 @@ def normalize_condition (property_sets): # FIXME push-checking-for-flags-module .... # FIXME: investigate existing uses of 'hack-hack' parameter # in jam code. - + +@bjam_signature((["rule_or_module", "variable_name", "condition", "*"], + ["values", "*"])) def flags (rule_or_module, variable_name, condition, values = []): """ Specifies the flags (variables) that must be set on targets under certain conditions, described by arguments. diff --git a/v2/engine/src/builtins.c b/v2/engine/src/builtins.c index 83bb1a2c4..2170af40e 100644 --- a/v2/engine/src/builtins.c +++ b/v2/engine/src/builtins.c @@ -1902,8 +1902,12 @@ PyObject* bjam_call( PyObject * self, PyObject * args ) /* - * Accepts three arguments: module name, rule name and Python callable. Creates - * a bjam rule with the specified name in the specified module, which will + * Accepts four arguments: + * - module name + * - rule name, + * - Python callable. + * - (optional) bjam language function signature. + * Creates a bjam rule with the specified name in the specified module, which will * invoke the Python callable. */ @@ -1912,10 +1916,12 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args ) char * module; char * rule; PyObject * func; + PyObject * bjam_signature = NULL; module_t * m; RULE * r; - if ( !PyArg_ParseTuple( args, "ssO:import_rule", &module, &rule, &func ) ) + if ( !PyArg_ParseTuple( args, "ssO|O:import_rule", + &module, &rule, &func, &bjam_signature ) ) return NULL; if ( !PyCallable_Check( func ) ) @@ -1932,6 +1938,22 @@ PyObject * bjam_import_rule( PyObject * self, PyObject * args ) Py_INCREF( func ); r->python_function = func; + r->arguments = 0; + + if (bjam_signature) + { + 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; + } Py_INCREF( Py_None ); return Py_None; diff --git a/v2/engine/src/compile.c b/v2/engine/src/compile.c index 02f508bd6..a07e0d818 100644 --- a/v2/engine/src/compile.c +++ b/v2/engine/src/compile.c @@ -707,6 +707,7 @@ collect_arguments( RULE* rule, FRAME* frame ) 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 ) @@ -722,6 +723,7 @@ collect_arguments( RULE* rule, FRAME* frame ) case '+': case '*': value = list_copy( 0, actual ); + multiple = 1; actual = 0; /* skip an extra element for the modifier */ formal = formal->next; @@ -738,7 +740,8 @@ collect_arguments( RULE* rule, FRAME* frame ) } } - locals = addsettings( locals, VAR_SET, name, value ); + locals = addsettings(locals, VAR_SET, name, value); + locals->multiple = multiple; type_check( type_name, value, frame, rule, arg_name ); type_name = 0; } @@ -764,28 +767,58 @@ static LIST* call_python_function(RULE* r, FRAME* frame) { LIST * result = 0; - PyObject * arguments = PyTuple_New( frame->args->count ); + PyObject * arguments = 0; + PyObject * kw = NULL; int i ; PyObject * py_result; - for ( i = 0; i < frame->args->count; ++i ) + if (r->arguments) { - PyObject * arg = PyList_New(0); - LIST* l = lol_get( frame->args, i); + SETTINGS * args; - for ( ; l; l = l->next ) + arguments = PyTuple_New(0); + kw = PyDict_New(); + + for (args = collect_arguments(r, frame); args; args = args->next) { - PyObject * v = PyString_FromString(l->string); - PyList_Append( arg, v ); - Py_DECREF(v); + 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 ); } - /* Steals reference to 'arg' */ - PyTuple_SetItem( arguments, i, arg ); } frame_before_python_call = frame; - py_result = PyObject_CallObject( r->python_function, arguments ); - Py_DECREF( arguments ); + py_result = PyObject_Call( r->python_function, arguments, kw ); + Py_DECREF(arguments); + Py_XDECREF(kw); if ( py_result != NULL ) { if ( PyList_Check( py_result ) ) diff --git a/v2/engine/src/lists.c b/v2/engine/src/lists.c index df0eff4d5..ebabb63e9 100644 --- a/v2/engine/src/lists.c +++ b/v2/engine/src/lists.c @@ -303,3 +303,37 @@ void lol_print( LOL * lol ) list_print( lol->list[ i ] ); } } + +#ifdef HAVE_PYTHON + +PyObject *list_to_python(LIST *l) +{ + PyObject *result = PyList_New(0); + + for (; l; l = l->next) + { + PyObject* s = PyString_FromString(l->string); + PyList_Append(result, s); + Py_DECREF(s); + } + + return result; +} + +LIST *list_from_python(PyObject *l) +{ + LIST * result = 0; + + 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))); + Py_DECREF(v); + } + + return result; +} + +#endif diff --git a/v2/engine/src/lists.h b/v2/engine/src/lists.h index ef5292397..1dc598274 100644 --- a/v2/engine/src/lists.h +++ b/v2/engine/src/lists.h @@ -45,6 +45,10 @@ #ifndef LISTS_DWA20011022_H # define LISTS_DWA20011022_H +#ifdef HAVE_PYTHON +#include +#endif + /* * LIST - list of strings */ @@ -93,5 +97,12 @@ LIST * lol_get( LOL *lol, int i ); void lol_print( LOL *lol ); void lol_build( LOL* lol, char** elements ); +#ifdef HAVE_PYTHON + +PyObject *list_to_python(LIST *l); +LIST *list_from_python(PyObject *l); + +#endif + #endif diff --git a/v2/engine/src/rules.c b/v2/engine/src/rules.c index 3d1a3a86e..a0be1d340 100644 --- a/v2/engine/src/rules.c +++ b/v2/engine/src/rules.c @@ -421,6 +421,7 @@ SETTINGS * addsettings( SETTINGS * head, int flag, char * symbol, LIST * value ) v->symbol = newstr( symbol ); v->value = value; v->next = head; + v->multiple = 0; head = v; } else if ( flag == VAR_APPEND ) diff --git a/v2/engine/src/rules.h b/v2/engine/src/rules.h index 78e056202..806a1469c 100644 --- a/v2/engine/src/rules.h +++ b/v2/engine/src/rules.h @@ -119,6 +119,7 @@ struct _settings SETTINGS * next; char * symbol; /* symbol name for var_set() */ LIST * value; /* symbol value for var_set() */ + int multiple; }; /* TARGETS - a chain of TARGETs. */ diff --git a/v2/util/__init__.py b/v2/util/__init__.py index e69de29bb..e64c0fc5e 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -0,0 +1,8 @@ + +def bjam_signature(s): + + def wrap(f): + f.bjam_signature = s + return f + + return wrap From 97aa32c3755282b0849a419c35193a0d527772a8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 14:50:16 +0000 Subject: [PATCH 009/165] New builtin SELF_PATH [SVN r64159] --- v2/engine/src/builtins.c | 21 ++++++++++++++ v2/engine/src/builtins.h | 1 + v2/engine/src/jam.c | 59 ++++++++++++++++++++++++++++++++++++++++ v2/engine/src/pathsys.h | 9 ++++++ 4 files changed, 90 insertions(+) diff --git a/v2/engine/src/builtins.c b/v2/engine/src/builtins.c index 2170af40e..39c8a7821 100644 --- a/v2/engine/src/builtins.c +++ b/v2/engine/src/builtins.c @@ -381,6 +381,11 @@ void load_builtins() builtin_precious, 0, args ); } + { + char * args [] = { 0 }; + bind_builtin( "SELF_PATH", builtin_self_path, 0, args ); + } + /* Initialize builtin modules. */ init_set(); init_path(); @@ -1707,6 +1712,22 @@ LIST *builtin_precious( PARSE *parse, FRAME *frame ) return L0; } +LIST *builtin_self_path( PARSE *parse, FRAME *frame ) +{ + extern char *saved_argv0; + char *p = executable_path (saved_argv0); + if (p) + { + LIST* result = list_new (0, newstr (p)); + free(p); + return result; + } + else + { + return L0; + } +} + #ifdef HAVE_PYTHON diff --git a/v2/engine/src/builtins.h b/v2/engine/src/builtins.h index 8ecc6616a..9ed3e6dc9 100644 --- a/v2/engine/src/builtins.h +++ b/v2/engine/src/builtins.h @@ -60,6 +60,7 @@ 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 ); void backtrace( FRAME *frame ); extern int last_update_now_status; diff --git a/v2/engine/src/jam.c b/v2/engine/src/jam.c index 2d06316e6..1ef741f83 100644 --- a/v2/engine/src/jam.c +++ b/v2/engine/src/jam.c @@ -210,6 +210,8 @@ int anyhow = 0; extern PyObject * bjam_backtrace ( PyObject * self, PyObject * args ); #endif +char *saved_argv0; + int main( int argc, char * * argv, char * * arg_environ ) { int n; @@ -221,6 +223,8 @@ int main( int argc, char * * argv, char * * arg_environ ) char * * arg_v = argv; char const * progname = argv[0]; + saved_argv0 = argv[0]; + BJAM_MEM_INIT(); # ifdef OS_MAC @@ -562,3 +566,58 @@ int main( int argc, char * * argv, char * * arg_environ ) return status ? EXITBAD : EXITOK; } + +#if defined(_WIN32) +#include +char *executable_path(char *arvg0) { + char buf[1024]; + DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf)); + if (ret == 0 || ret == sizeof(buf)) return NULL; + return strdup (buf); +} +#elif defined(__APPLE__) // Not tested +#include +char *executable_path(char *arvg0) { + char buf[1024]; + uint32_t size = sizeof(buf); + int ret = _NSGetExecutablePath(buf, &size); + if (ret != 0) return NULL; + return strdup(buf); +} +#elif defined(sun) || defined(__sun) // Not tested +#include + +char *executable_path(char *arvg0) { + return stdrup(getexecname()); +} +#elif defined(__FreeBSD__) +#include +char *executable_path(char *arvg0) { + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char buf[1024]; + size_t size = sizeof(buf); + sysctl(mib, 4, buf, &size, NULL, 0); + if (size == 0 || size == sizeof(buf)) return NULL; + return strndup(buf, size); +} +#elif defined(__linux__) +#include +char *executable_path(char *arvg0) { + 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 *arvg0) { + // If argv0 is absolute path, assume it's the right + // absolute path. + if (argv0[0] == "/") + return strdup(argv0); + return NULL; +} +#endif diff --git a/v2/engine/src/pathsys.h b/v2/engine/src/pathsys.h index 49d2bf8e2..737758105 100644 --- a/v2/engine/src/pathsys.h +++ b/v2/engine/src/pathsys.h @@ -79,4 +79,13 @@ const char * path_tmpnam( void ); const char * path_tmpfile( void ); #endif +/** Give the first argument to 'main', return a full path to + our executable. Returns null in the unlikely case it + cannot be determined. Caller is responsible for freeing + the string. + + Implemented in jam.c +*/ +char * executable_path (char *argv0); + #endif From bd52f9610337fa13ad98480e6f202393bd449fc7 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 19:32:32 +0000 Subject: [PATCH 010/165] Perform bjam-relative search for Boost.Build proper. This allows to make installed Boost.Build work without setting any environment variables or config files. [SVN r64165] --- v2/engine/src/Jambase | 5 +++++ v2/engine/src/jambase.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/v2/engine/src/Jambase b/v2/engine/src/Jambase index 5a9449983..467d52571 100644 --- a/v2/engine/src/Jambase +++ b/v2/engine/src/Jambase @@ -128,9 +128,13 @@ if [ MATCH .*(bjam).* : $(ARGV[1]:BL) ] # Boost.Build files. local search-path = $(BOOST_BUILD_PATH) $(BOOST_ROOT) ; + local self = [ SELF_PATH ] ; + local boost-build-relative = ../../share/boost-build ; + local self-based-path = [ NORMALIZE_PATH $(boost-build-relative:R=$(self)) ] ; local boost-build-files = [ find-to-root [ PWD ] : boost-build.jam ] + [ GLOB $(self-based-path) : boost-build.jam ] # Another temporary measure so Jam works with Boost.Build v1. [ GLOB $(search-path) : boost-build.jam ] ; @@ -152,6 +156,7 @@ if [ MATCH .*(bjam).* : $(ARGV[1]:BL) ] } ECHO "Attempted search from" [ PWD ] "up to the root" ; + ECHO "at" $(self-based-path) ; ECHO "and in these directories from BOOST_BUILD_PATH and BOOST_ROOT: "$(search-path:J=", ")"." ; EXIT "Please consult the documentation at 'http://www.boost.org'." ; } diff --git a/v2/engine/src/jambase.c b/v2/engine/src/jambase.c index dbcf263e3..d89f3c54d 100644 --- a/v2/engine/src/jambase.c +++ b/v2/engine/src/jambase.c @@ -68,8 +68,12 @@ char *jambase[] = { "|| $(BOOST_ROOT) # A temporary measure so Jam works with Boost.Build v1.\n", "{\n", "local search-path = $(BOOST_BUILD_PATH) $(BOOST_ROOT) ;\n", +"local self = [ SELF_PATH ] ;\n", +"local boost-build-relative = ../../share/boost-build ;\n", +"local self-based-path = [ NORMALIZE_PATH $(boost-build-relative:R=$(self)) ] ;\n", "local boost-build-files =\n", "[ find-to-root [ PWD ] : boost-build.jam ]\n", +"[ GLOB $(self-based-path) : boost-build.jam ]\n", "[ GLOB $(search-path) : boost-build.jam ] ;\n", ".boost-build-file = $(boost-build-files[1]) ;\n", "if ! $(.boost-build-file)\n", @@ -84,6 +88,7 @@ char *jambase[] = { "ECHO ;\n", "}\n", "ECHO \"Attempted search from\" [ PWD ] \"up to the root\" ;\n", +"ECHO \"at\" $(self-based-path) ;\n", "ECHO \"and in these directories from BOOST_BUILD_PATH and BOOST_ROOT: \"$(search-path:J=\", \")\".\" ;\n", "EXIT \"Please consult the documentation at 'http://www.boost.org'.\" ;\n", "}\n", From cfe25ebe483b6bf179902a4709d0a84d6f793b0e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 19:48:27 +0000 Subject: [PATCH 011/165] Implement 'bootstrap' + 'bjam install' installation for Boost.Build. [SVN r64166] --- v2/bootstrap.bat | 47 +++++++++++++++++++ v2/bootstrap.sh | 107 +++++++++++++++++++++++++++++++++++++++++++ v2/build.jam | 35 ++++++++++++++ v2/tools/package.jam | 54 +++++++++++++++++----- 4 files changed, 232 insertions(+), 11 deletions(-) create mode 100644 v2/bootstrap.bat create mode 100755 v2/bootstrap.sh create mode 100644 v2/build.jam diff --git a/v2/bootstrap.bat b/v2/bootstrap.bat new file mode 100644 index 000000000..f3c0af5ca --- /dev/null +++ b/v2/bootstrap.bat @@ -0,0 +1,47 @@ +@ECHO OFF + +REM Copyright (C) 2009 Vladimir Prus +REM +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) + +ECHO Bootstrapping the build engine +if exist ".\engine\src\bin.ntx86\bjam.exe" del tools\build\v2\engine\src\bin.ntx86\bjam.exe +if exist ".\engine\src\bin.ntx86_64\bjam.exe" del tools\build\v2\engine\src\bin.ntx86_64\bjam.exe +cd engine\src + +call .\build.bat > ..\bootstrap.log +@ECHO OFF +cd ..\..\.. + +if exist ".\engine\src\bin.ntx86\bjam.exe" ( + copy .\engine\src\bin.ntx86\bjam.exe . > nul + goto :bjam_built) + +if exist ".\engine\src\bin.ntx86_64\bjam.exe" ( + copy .\engine\src\bin.ntx86_64\bjam.exe . > nul + goto :bjam_built) + +goto :bjam_failure + +:bjam_built + +ECHO. +ECHO Bootstrapping is done. To build, run: +ECHO. +ECHO .\bjam --prefix=DIR install +ECHO. + +goto :end + +:bjam_failure + +ECHO. +ECHO Failed to bootstrap the build engine +ECHO Please consult bootstrap.log for furter diagnostics. +ECHO. + + +goto :end + +:end diff --git a/v2/bootstrap.sh b/v2/bootstrap.sh new file mode 100755 index 000000000..ddc2c0217 --- /dev/null +++ b/v2/bootstrap.sh @@ -0,0 +1,107 @@ +#!/bin/sh +# Copyright (C) 2005, 2006 Douglas Gregor. +# Copyright (C) 2006 The Trustees of Indiana University +# +# 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) + +# boostinspect:notab - Tabs are required for the Makefile. + +BJAM="" +TOOLSET="" +BJAM_CONFIG="" + +for option +do + case $option in + + -help | --help | -h) + want_help=yes ;; + + -with-toolset=* | --with-toolset=* ) + TOOLSET=`expr "x$option" : "x-*with-toolset=\(.*\)"` + ;; + + -*) + { echo "error: unrecognized option: $option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + esac +done + +if test "x$want_help" = xyes; then + cat < bootstrap.log 2>&1 + if [ $? -ne 0 ]; then + echo + echo "Failed to bootstrap the build engine" + echo "Consult 'bootstrap.log' for more details" + exit 1 + fi + cd "$pwd" + arch=`cd $my_dir/engine/src && ./bootstrap/jam0 -d0 -f build.jam --toolset=$TOOLSET --toolset-root= --show-locate-target && cd ..` + BJAM="$my_dir/engine/src/$arch/bjam" + echo "engine/src/$arch/bjam" + cp "$BJAM" . +fi + +cat << EOF + +Bootstrapping is done. To build and install, run: + + ./bjam install --prefix= + +EOF \ No newline at end of file diff --git a/v2/build.jam b/v2/build.jam new file mode 100644 index 000000000..d30ad1c6c --- /dev/null +++ b/v2/build.jam @@ -0,0 +1,35 @@ + +path-constant SELF : . ; + +import path ; +import package ; +import os ; + +local ext = "" ; +if [ os.on-windows ] +{ + ext = ".exe" ; +} + + +package.install boost-build-engine + : # properties + : # binaries + bjam$(ext) + ; + +package.install-data boost-build-core + : # Which subdir of $prefix/share + boost-build + : # What to install + $(SELF)/boost-build.jam + $(SELF)/build-system.jam + [ 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 ] + : # What is the root of the directory + . + ; + +alias install : boost-build-engine boost-build-core ; \ No newline at end of file diff --git a/v2/tools/package.jam b/v2/tools/package.jam index 36f22c578..c96ea3d3b 100644 --- a/v2/tools/package.jam +++ b/v2/tools/package.jam @@ -67,17 +67,7 @@ rule install ( name : requirements * : binaries * : libraries * : headers * ) # First, figure out all locations. Use the default if no prefix option # given. - local prefix = [ option.get prefix : [ property.select - : $(requirements) ] ] ; - prefix = $(prefix:G=) ; - requirements = [ property.change $(requirements) : - ] ; - # Or some likely defaults if neither is given. - if ! $(prefix) - { - if [ modules.peek : NT ] { prefix = C:\\$(name) ; } - else if [ modules.peek : UNIX ] { prefix = /usr/local ; } - } + local prefix = [ get-prefix $(requirements) ] ; # Architecture dependent files. local exec-locate = [ option.get exec-prefix : $(prefix) ] ; @@ -126,3 +116,45 @@ rule install ( name : requirements * : binaries * : libraries * : headers * ) $(1)-lib-shared-universe $(1)-lib-shared-cygwin ; } } + +rule install-data ( target-name : directory-name : data * : requirements * ) +{ + if [ MATCH --prefix=(.*) : [ modules.peek : ARGV ] ] + { + # If --prefix is explicitly specified on the command line, + # then we need wipe away any settings of datarootdir + option.set datarootdir : ; + } + + local prefix = [ get-prefix $(requirements) ] ; + local datadir = [ option.get datarootdir : $(prefix)/share ] ; + + stage.install $(target-name) + : $(data) + : $(requirements) $(datadir)/$(directory-name) + ; + + local c = [ project.current ] ; + local project-module = [ $(c).project-module ] ; + module $(project-module) + { + explicit $(1) ; + } +} + +local rule get-prefix ( requirements * ) +{ + local prefix = [ option.get prefix : [ property.select + : $(requirements) ] ] ; + prefix = $(prefix:G=) ; + requirements = [ property.change $(requirements) : + ] ; + # Or some likely defaults if neither is given. + if ! $(prefix) + { + if [ modules.peek : NT ] { prefix = C:\\$(name) ; } + else if [ modules.peek : UNIX ] { prefix = /usr/local ; } + } + return $(prefix) ; +} + From 76e7e1e4f6b7b0b0f71bdc64d2fad520fd3f96f1 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 19 Jul 2010 20:47:06 +0000 Subject: [PATCH 012/165] Fix paths [SVN r64176] --- v2/bootstrap.bat | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v2/bootstrap.bat b/v2/bootstrap.bat index f3c0af5ca..d2f0100d1 100644 --- a/v2/bootstrap.bat +++ b/v2/bootstrap.bat @@ -6,13 +6,13 @@ 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) ECHO Bootstrapping the build engine -if exist ".\engine\src\bin.ntx86\bjam.exe" del tools\build\v2\engine\src\bin.ntx86\bjam.exe -if exist ".\engine\src\bin.ntx86_64\bjam.exe" del tools\build\v2\engine\src\bin.ntx86_64\bjam.exe +if exist ".\engine\src\bin.ntx86\bjam.exe" del engine\src\bin.ntx86\bjam.exe +if exist ".\engine\src\bin.ntx86_64\bjam.exe" del engine\src\bin.ntx86_64\bjam.exe cd engine\src -call .\build.bat > ..\bootstrap.log +call .\build.bat > ..\..\bootstrap.log @ECHO OFF -cd ..\..\.. +cd ..\.. if exist ".\engine\src\bin.ntx86\bjam.exe" ( copy .\engine\src\bin.ntx86\bjam.exe . > nul From 2400d8e6ebf50cb9fea7186ebf49d62c0d565390 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 08:13:06 +0000 Subject: [PATCH 013/165] Simplify setup [SVN r64188] --- v2/example/customization/jamfile.jam | 7 ------- v2/example/customization/jamroot.jam | 5 ++++- 2 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 v2/example/customization/jamfile.jam diff --git a/v2/example/customization/jamfile.jam b/v2/example/customization/jamfile.jam deleted file mode 100644 index eee0f4f4c..000000000 --- a/v2/example/customization/jamfile.jam +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright 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) - - -exe codegen : codegen.cpp class.verbatim usage.verbatim - t1.verbatim ; diff --git a/v2/example/customization/jamroot.jam b/v2/example/customization/jamroot.jam index ab8bbf880..5e986d91c 100644 --- a/v2/example/customization/jamroot.jam +++ b/v2/example/customization/jamroot.jam @@ -2,5 +2,8 @@ # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) - import verbatim ; + +exe codegen : codegen.cpp class.verbatim usage.verbatim + t1.verbatim ; + From c630b3c2078b85068d016e08d00b531738b47519 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 08:22:18 +0000 Subject: [PATCH 014/165] Move Boost.Jam docs to where Boost.Build docs are. [SVN r64189] --- v2/{engine => }/doc/bjam.qbk | 0 v2/{engine => }/doc/history.qbk | 0 v2/doc/jamfile.jam | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename v2/{engine => }/doc/bjam.qbk (100%) rename v2/{engine => }/doc/history.qbk (100%) diff --git a/v2/engine/doc/bjam.qbk b/v2/doc/bjam.qbk similarity index 100% rename from v2/engine/doc/bjam.qbk rename to v2/doc/bjam.qbk diff --git a/v2/engine/doc/history.qbk b/v2/doc/history.qbk similarity index 100% rename from v2/engine/doc/history.qbk rename to v2/doc/history.qbk diff --git a/v2/doc/jamfile.jam b/v2/doc/jamfile.jam index 22777cf06..7c946a453 100644 --- a/v2/doc/jamfile.jam +++ b/v2/doc/jamfile.jam @@ -17,7 +17,7 @@ boostbook userman : src/standalone.xml boost.root=../../../../.. ; -xml jam_docs : ../../../jam/doc/bjam.qbk ; +xml jam_docs : bjam.qbk ; if ! $(BOOST_ROOT) { From 107bff7d8f57d8d8a994f92f6363851531bb0507 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 08:23:53 +0000 Subject: [PATCH 015/165] Remove now-empty Boost.Jam docs directory. [SVN r64190] --- v2/engine/doc/build.jam | 42 ----------------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 v2/engine/doc/build.jam diff --git a/v2/engine/doc/build.jam b/v2/engine/doc/build.jam deleted file mode 100644 index 5d137c484..000000000 --- a/v2/engine/doc/build.jam +++ /dev/null @@ -1,42 +0,0 @@ -project tools/jam/doc ; - -import path ; - -using quickbook ; - -xml bjam - : - bjam.qbk - ; - -stage html - : - ../../../LICENSE_1_0.txt - ../../../boost.png - ../../../doc/src/boostbook.css - ; - -stage html/images - : - [ path.glob ../../../doc/src/images : *.png ] - ; - -boostbook standalone - : - bjam - : - #html - html - html - html/images - boost.root=. - -boost.defaults=Boost - nav.layout=none - boost.image=Boost - html:admon.graphics.path=images/ - html:navig.graphics.path=images/ - ; - -# Copyright Rene Rivera 2005-2006. Use, modification, and distribution are -# subject to the Boost Software License, Version 1.0. (See accompanying -# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) From 0382b22cd8e966d56d4cf86b7e7f65b43bd6b69c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 08:37:11 +0000 Subject: [PATCH 016/165] Make this a standalone project [SVN r64191] --- v2/{build.jam => Jamroot.jam} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename v2/{build.jam => Jamroot.jam} (100%) diff --git a/v2/build.jam b/v2/Jamroot.jam similarity index 100% rename from v2/build.jam rename to v2/Jamroot.jam From dd7fca15d09a0c036778c20b295a6cb3024e10b6 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 08:51:03 +0000 Subject: [PATCH 017/165] Update nightly build scripts. [SVN r64192] --- v2/nightly.sh | 9 +++++---- v2/roll.sh | 12 +++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/v2/nightly.sh b/v2/nightly.sh index 7b6c85c6a..0d9f310c0 100755 --- a/v2/nightly.sh +++ b/v2/nightly.sh @@ -16,11 +16,12 @@ export LC_ALL=C export LC_MESSAGES=C export LANG=C cd /tmp -rm -rf boost-build +rm -rf boost-build-nightly +mkdir boost-build-nightly echo "Checking out sources" -svn co http://svn.boost.org/svn/boost/trunk/tools boost-build > /tmp/boost_build_checkout_log -mv /tmp/boost_build_checkout_log boost-build/checkout-log -cd boost-build/build/v2 +svn co http://svn.boost.org/svn/boost/trunk/tools/build/v2 boost-build-nightly/boost-build > /tmp/boost_build_checkout_log +mv /tmp/boost_build_checkout_log boost-build-nightly/checkout-log +cd boost-build-nightly/boost-build/ echo "Building packages and uploading docs" ./roll.sh > ../roll-log 2>&1 cd .. diff --git a/v2/roll.sh b/v2/roll.sh index 829c56eed..3b8eb82a1 100755 --- a/v2/roll.sh +++ b/v2/roll.sh @@ -8,14 +8,8 @@ set -e -# Do some renames/rearrangments -cp -r ../v2 ../boost-build -# Grab jam_src -cp -r ../../jam/src ../boost-build/jam_src -cd ../boost-build - # Capture the version -revision=`svnversion ..` +revision=`svnversion .` echo "SVN Revision $revision" >> timestamp.txt date >> timestamp.txt @@ -23,7 +17,7 @@ date >> timestamp.txt rm -rf example/versioned # Remove unnecessary top-level files -find . -maxdepth 1 -type f | egrep -v "boost-build.jam|timestamp.txt|roll.sh|bootstrap.jam|build-system.jam|boost_build.png|index.html|hacking.txt|site-config.jam|user-config.jam" | xargs rm -f +find . -maxdepth 1 -type f | egrep -v "boost-build.jam|timestamp.txt|roll.sh|bootstrap.jam|build-system.jam|boost_build.png|index.html|hacking.txt|site-config.jam|user-config.jam|bootstrap.sh|bootstrap.bat|Jamroot.jam" | xargs rm -f # Build the documentation touch doc/jamroot.jam @@ -48,7 +42,7 @@ perl -pi -e 's%../../../doc/html/bbv2.installation.html%doc/html/bbv2.installati # Make packages find . -name ".svn" | xargs rm -rf rm roll.sh -chmod a+x jam_src/build.bat +chmod a+x engine/src/build.bat cd .. && zip -r boost-build.zip boost-build && tar --bzip2 -cf boost-build.tar.bz2 boost-build # Copy packages to a location where they are grabbed for beta.boost.org cp userman.pdf boost-build.zip boost-build.tar.bz2 ~/public_html/boost_build_nightly From 1735285372a0ec766140523e3eea272af50f9650 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 09:02:26 +0000 Subject: [PATCH 018/165] Install examples, too [SVN r64193] --- v2/Jamroot.jam | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/v2/Jamroot.jam b/v2/Jamroot.jam index d30ad1c6c..3403c2083 100644 --- a/v2/Jamroot.jam +++ b/v2/Jamroot.jam @@ -18,6 +18,16 @@ package.install boost-build-engine bjam$(ext) ; +local e1 = [ path.glob-tree $(SELF)/example : * : . .svn ] ; +local e2 ; +for e in $(e1) +{ + if [ CHECK_IF_FILE $(e) ] + { + e2 += $(e) ; + } +} + package.install-data boost-build-core : # Which subdir of $prefix/share boost-build @@ -28,6 +38,7 @@ package.install-data boost-build-core [ path.glob-tree $(SELF)/kernel : *.jam *.py ] [ path.glob-tree $(SELF)/util : *.jam *.py ] [ path.glob-tree $(SELF)/tools : *.jam *.py ] + $(e2) : # What is the root of the directory . ; From 1023b783027de6d7889af456db4002ea486d6953 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 09:22:20 +0000 Subject: [PATCH 019/165] Adjust install docs for current improvements [SVN r64194] --- v2/doc/src/install.xml | 164 +++++++++++------------------------------ 1 file changed, 43 insertions(+), 121 deletions(-) diff --git a/v2/doc/src/install.xml b/v2/doc/src/install.xml index 3dd30bf1e..274f269a0 100644 --- a/v2/doc/src/install.xml +++ b/v2/doc/src/install.xml @@ -6,92 +6,57 @@ Installation - This section describes how to install Boost.Build from a - released Boost - source distribution - or CVS - image. - - Note that packages prepared for - Unix/Linux systems usually make their own choices about where to - put things and even which parts of Boost to include. When we - say “released source distribution” we mean a - distribution of Boost as released on its SourceForge - project - page. - - -All paths are given relative to - the Boost.Build v2 root directory, which is - - - - - - located in the tools/build/v2 subdirectory - of a full Boost distribution. - - The Boost.Build subset of boost is also distributed - separately, for those who are only interested in getting a - build tool. The top-level directory of a Boost.Build - distribution contains all the subdirectories of the - tools/build/v2 subdirectory from a full - Boost distribution, so it is itself a valid Boost.Build root - directory. It also contains the - tools/jam/src subdirectory of a - full Boost distribution, so you can rebuild Boost.Jam from - source. - - + To install Boost.Build from an official release or a nightly build, as + available on the official web site, + follow these steps: - Boost.Build uses Boost.Jam, an - extension of the Perforce - Jam portable make replacement. The - recommended way to get Boost.Jam is to download - a prebuilt executable from SourceForge. - If a prebuilt executable is not provided for your platform - or you are using Boost's sources in an unreleased state, it - may be necessary to - build bjam - from sources included in the Boost source tree. + Unpack the release. On the command line, go to the root of the + unpacked tree. - - - To install Boost.Jam, copy the executable, - called bjam - or bjam.exe to a location accessible in - your PATH. Go to the Boost.Build root - directory and - run bjam . You - should see: - - - Boost.Build V2 (Milestone N) - Boost.Jam xx.xx.xx - - - where N is the version of Boost.Build you're using. - + + Run either .\bootstrap.bat (on Windows), or + ./bootstrap.sh (on other operating systmes). + + Run + +./bjam install --prefix=PREFIX + + where PREFIX is a directory where you + want Boost.Build to be installed. + + + + + + Optionally, add PREFIX/bin + to your PATH environment variable. + + + + + + Now that Boost.Build is installed, you can try some of examples. Copy + PREFIX/share/boost-build/examples/hello + to a different directory, then change to that directory and run: + +PREFIX/bin/bjam + + A simple executable should be build. + + + - - - You should now be able to go to the - example/hello/ directory and run - bjam there. A simple application will be - built. You can also play with other projects in the - example/ directory. - - - - - If you are using Boost's CVS state, be sure to - rebuild bjam even if you have a previous - version. The CVS version of Boost.Build requires the CVS - version of Boost.Jam. - - - - When bjam is invoked, it always needs to be - able to find the Boost.Build root directory, where the - interpreted source code of Boost.Build is located. There are - two ways to tell bjam about the root directory: - - - - - - Set the environment variable BOOST_BUILD_PATH - to the absolute path of the Boost.Build root directory. - - - - - - At the root directory of your project or in any of its - parent directories, create a file called - boost-build.jam, with a single line: - - -boost-build /path/to/boost.build ; - - - - - - - Information for distributors + + From f695c5c372bb442fe65b01c3221052cdb3e359b9 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 10:31:26 +0000 Subject: [PATCH 020/165] Mention where Boost.Build is located inside Boost C++ Libraries. [SVN r64195] --- v2/doc/src/install.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/v2/doc/src/install.xml b/v2/doc/src/install.xml index 274f269a0..526606fd6 100644 --- a/v2/doc/src/install.xml +++ b/v2/doc/src/install.xml @@ -29,9 +29,7 @@ Run - -./bjam install --prefix=PREFIX - + ./bjam install --prefix=PREFIX where PREFIX is a directory where you want Boost.Build to be installed. @@ -45,13 +43,15 @@ + If you are not using Boost.Build package, but rather the version + bundled with the Boost C++ Libraries, the above commands should be run + in the tools/build/v2 directory. + Now that Boost.Build is installed, you can try some of examples. Copy PREFIX/share/boost-build/examples/hello to a different directory, then change to that directory and run: - -PREFIX/bin/bjam - +PREFIX/bin/bjam A simple executable should be build. From df4c927edcbc084f2701140d1762efcfe6d6d2f0 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 15:16:13 +0000 Subject: [PATCH 021/165] Support for Boost.Build/Python [SVN r64201] --- v2/example/customization/verbatim.py | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 v2/example/customization/verbatim.py diff --git a/v2/example/customization/verbatim.py b/v2/example/customization/verbatim.py new file mode 100644 index 000000000..be285976c --- /dev/null +++ b/v2/example/customization/verbatim.py @@ -0,0 +1,47 @@ +# Copyright 2010 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 file is only used with Python port of Boost.Build + +# This file shows some of the primary customization mechanisms in Boost.Build V2 +# and should serve as a basic for your own customization. +# Each part has a comment describing its purpose, and you can pick the parts +# which are relevant to your case, remove everything else, and then change names +# and actions to taste. + +# Declare a new target type. This allows Boost.Build to do something sensible +# when targets with the .verbatim extension are found in sources. +import b2.build.type as type +type.register("VERBATIM", ["verbatim"]) + +# Declare a dependency scanner for the new target type. The +# 'inline-file.py' script does not handle includes, so this is +# only for illustraction. +import b2.build.scanner as scanner; +# First, define a new class, derived from 'common-scanner', +# that class has all the interesting logic, and we only need +# to override the 'pattern' method which return regular +# expression to use when scanning. +class VerbatimScanner(scanner.CommonScanner): + + def pattern(self): + return "//###include[ ]*\"([^\"]*)\"" + +scanner.register(VerbatimScanner, ["include"]) +type.set_scanner("VERBATIM", VerbatimScanner) + +import b2.build.generators as generators + +generators.register_standard("verbatim.inline-file", + ["VERBATIM"], ["CPP"]) + +from b2.manager import get_manager + +get_manager().engine().register_action("verbatim.inline-file", +""" +./inline_file.py $(<) $(>) +""") + + + From 284a2f0608f4e5ad71cd0b7c110bddde3fcde864 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 15:23:33 +0000 Subject: [PATCH 022/165] Fix various bugs [SVN r64202] --- v2/build/scanner.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/v2/build/scanner.py b/v2/build/scanner.py index 63f286994..fdb0addcf 100644 --- a/v2/build/scanner.py +++ b/v2/build/scanner.py @@ -31,6 +31,7 @@ import property import bjam +import os from b2.exceptions import * from b2.manager import get_manager @@ -103,7 +104,7 @@ class Scanner: # Common scanner class, which can be used when there's only one # kind of includes (unlike C, where "" and <> includes have different # search paths). -def CommonScanner(Scanner): +class CommonScanner(Scanner): def __init__ (self, includes): Scanner.__init__(self) @@ -114,8 +115,8 @@ def CommonScanner(Scanner): target_path = os.path.normpath(os.path.dirname(binding[0])) bjam.call("mark-included", target, matches) - engine.set_target_variable(matches, "SEARCH", - [target_path] + self.includes_) + get_manager().engine().set_target_variable(matches, "SEARCH", + [target_path] + self.includes) get_manager().scanners().propagate(self, matches) class ScannerRegistry: From 62e4971d9aba9978c6996dce91823ca8c6f03bcb Mon Sep 17 00:00:00 2001 From: "K. Noel Belcourt" Date: Tue, 20 Jul 2010 16:26:40 +0000 Subject: [PATCH 023/165] Fix typo stdrup with strdup. This typo was in code section conditional on Sun and the Sun nightly builds broke making this easy to track down. [SVN r64203] --- v2/engine/src/jam.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/engine/src/jam.c b/v2/engine/src/jam.c index 1ef741f83..68bcba42d 100644 --- a/v2/engine/src/jam.c +++ b/v2/engine/src/jam.c @@ -588,7 +588,7 @@ char *executable_path(char *arvg0) { #include char *executable_path(char *arvg0) { - return stdrup(getexecname()); + return strdup(getexecname()); } #elif defined(__FreeBSD__) #include From a24d91c8d5333d1843168993e1462498c4b3c326 Mon Sep 17 00:00:00 2001 From: "K. Noel Belcourt" Date: Tue, 20 Jul 2010 17:13:19 +0000 Subject: [PATCH 024/165] Replace C++ (//) comments with C block comments (/* ... */). This is one problem killing Itanium builds. One more to go. [SVN r64204] --- v2/engine/src/jam.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/v2/engine/src/jam.c b/v2/engine/src/jam.c index 68bcba42d..99045441f 100644 --- a/v2/engine/src/jam.c +++ b/v2/engine/src/jam.c @@ -575,7 +575,7 @@ char *executable_path(char *arvg0) { if (ret == 0 || ret == sizeof(buf)) return NULL; return strdup (buf); } -#elif defined(__APPLE__) // Not tested +#elif defined(__APPLE__) /* Not tested */ #include char *executable_path(char *arvg0) { char buf[1024]; @@ -584,7 +584,7 @@ char *executable_path(char *arvg0) { if (ret != 0) return NULL; return strdup(buf); } -#elif defined(sun) || defined(__sun) // Not tested +#elif defined(sun) || defined(__sun) /* Not tested */ #include char *executable_path(char *arvg0) { @@ -614,8 +614,7 @@ char *executable_path(char *arvg0) { } #else char *executable_path(char *arvg0) { - // If argv0 is absolute path, assume it's the right - // absolute path. + /* If argv0 is absolute path, assume it's the right absolute path. */ if (argv0[0] == "/") return strdup(argv0); return NULL; From 318020a0797af33511a2c9aa115183d27490a9e3 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 20 Jul 2010 19:18:06 +0000 Subject: [PATCH 025/165] Compile on cygwin. [SVN r64207] --- v2/engine/src/jam.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/v2/engine/src/jam.c b/v2/engine/src/jam.c index 99045441f..f76546d8e 100644 --- a/v2/engine/src/jam.c +++ b/v2/engine/src/jam.c @@ -569,7 +569,7 @@ int main( int argc, char * * argv, char * * arg_environ ) #if defined(_WIN32) #include -char *executable_path(char *arvg0) { +char *executable_path(char *argv0) { char buf[1024]; DWORD ret = GetModuleFileName(NULL, buf, sizeof(buf)); if (ret == 0 || ret == sizeof(buf)) return NULL; @@ -577,7 +577,7 @@ char *executable_path(char *arvg0) { } #elif defined(__APPLE__) /* Not tested */ #include -char *executable_path(char *arvg0) { +char *executable_path(char *argv0) { char buf[1024]; uint32_t size = sizeof(buf); int ret = _NSGetExecutablePath(buf, &size); @@ -587,12 +587,12 @@ char *executable_path(char *arvg0) { #elif defined(sun) || defined(__sun) /* Not tested */ #include -char *executable_path(char *arvg0) { +char *executable_path(char *argv0) { return strdup(getexecname()); } #elif defined(__FreeBSD__) #include -char *executable_path(char *arvg0) { +char *executable_path(char *argv0) { int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; @@ -606,14 +606,14 @@ char *executable_path(char *arvg0) { } #elif defined(__linux__) #include -char *executable_path(char *arvg0) { +char *executable_path(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 *arvg0) { +char *executable_path(char *argv0) { /* If argv0 is absolute path, assume it's the right absolute path. */ if (argv0[0] == "/") return strdup(argv0); From e46cbd6a2f8a267563949e7285097b4ddcef8a78 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 21 Jul 2010 11:04:12 +0000 Subject: [PATCH 026/165] Fix search for Boost.Jam in Boost.Build testing [SVN r64217] --- v2/test/BoostBuild.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 612ede70b..1a6169db5 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -244,8 +244,8 @@ class Tester(TestCmd.TestCmd): # Find where jam_src is located. Try for the debug version if it is # lying around. - dirs = [os.path.join('../../../jam/src', jam_build_dir + '.debug'), - os.path.join('../../../jam/src', jam_build_dir), + dirs = [os.path.join('../engine/src', jam_build_dir + '.debug'), + os.path.join('../engine/src', jam_build_dir), ] for d in dirs: if os.path.exists(d): From 58cfa3c7bd452fe0320abbe925106903c7ce52c0 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 09:04:47 +0000 Subject: [PATCH 027/165] Remove debug print [SVN r64285] --- v2/tools/gcc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/v2/tools/gcc.py b/v2/tools/gcc.py index 2ec33075d..3b280e3d9 100644 --- a/v2/tools/gcc.py +++ b/v2/tools/gcc.py @@ -287,7 +287,6 @@ flags('gcc.compile', 'OPTIONS', ['off'], ['-fno-rtti']) # In that case we'll just add another parameter to 'init' and move this login # inside 'init'. if not os_name () in ['CYGWIN', 'NT']: - print "osname:", os_name() # This logic will add -fPIC for all compilations: # # lib a : a.cpp b ; From 462dff1e1be777c984c249706748d50c4283f895 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 09:09:14 +0000 Subject: [PATCH 028/165] Introduce Feature and Property classes, and move away from messy string manipulation. [SVN r64286] --- v2/build/build_request.py | 107 ++++---- v2/build/errors.py | 7 +- v2/build/feature.py | 543 ++++++++++++++++++------------------- v2/build/property.py | 253 ++++++++--------- v2/build/property_set.py | 150 +++++++--- v2/build/targets.py | 14 +- v2/build/toolset.py | 128 ++++----- v2/build/virtual_target.py | 4 +- v2/build_system.py | 6 +- v2/tools/builtin.py | 34 +-- 10 files changed, 622 insertions(+), 624 deletions(-) diff --git a/v2/build/build_request.py b/v2/build/build_request.py index 9fd29e974..8684b8320 100644 --- a/v2/build/build_request.py +++ b/v2/build/build_request.py @@ -16,71 +16,72 @@ def expand_no_defaults (property_sets): specify conflicting non-free features. """ # First make all features and subfeatures explicit - expanded_property_sets = [ __apply_to_property_set (feature.expand_subfeatures, x) for x in property_sets ] + expanded_property_sets = [ps.expand_subfeatures() for ps in property_sets] # Now combine all of the expanded property_sets product = __x_product (expanded_property_sets) return product -def __apply_to_property_set (f, property_set): - """ Transform property_set by applying f to each component property. - """ - properties = feature.split (property_set) - return '/'.join (f (properties)) - - def __x_product (property_sets): """ Return the cross-product of all elements of property_sets, less any that would contain conflicting values for single-valued features. """ - x_product_seen = [] - x_product_used = [] - feature_space = [] - return __x_product_aux (property_sets, x_product_seen, x_product_used, feature_space) - -def __x_product_aux (property_sets, x_product_seen, x_product_used, feature_space): - """ Implementation of __x_product. - """ - result = [] - - if property_sets: - p = feature.split (property_sets [0]) - else: - p = [] - - f = set.difference (get_grist (p), feature.free_features ()) - - seen = [] - # No conflict with things used at a higher level? - if not set.intersection (f, x_product_used): - # don't mix in any conflicting features - local_x_product_used = x_product_used + f - local_x_product_seen = [] - - if len (property_sets) > 1: - rest = __x_product_aux (property_sets [1:], local_x_product_seen, local_x_product_used, feature_space) - result = [ property_sets [0] + '/' + x for x in rest] - - if not result and property_sets: - result = [property_sets [0]] - - # If we didn't encounter a conflicting feature lower down, - # don't recurse again. - if not set.intersection (f, local_x_product_seen): - property_sets = [] - - seen = local_x_product_seen - - if len (property_sets) > 1: - result.extend (__x_product_aux (property_sets [1:], x_product_seen, x_product_used, feature_space)) - x_product_seen += f + seen - - # Note that we've seen these features so that higher levels will - # recurse again without them set. + x_product_seen = set() + x_product_used = set() + return __x_product_aux (property_sets, x_product_seen, x_product_used) - return result +def __x_product_aux (property_sets, seen_features): + """Returns non-conflicting combinations of property sets. + + property_sets is a list of PropertySet instances. seen_features is a set of Property + instances. + + Returns a tuple of: + - list of lists of Property instances, such that within each list, no two Property instance + have the same feature, and no Property is for feature in seen_features. + - set of features we saw in property_sets + """ + if not property_sets: + return ([], set()) + + properties = property_sets[0].all() + + these_features = set() + for p in property_sets[0].non_free(): + these_features.add(p.feature()) + + # Note: the algorithm as implemented here, as in original Jam code, appears to + # detect conflicts based on features, not properties. For example, if command + # line build request say: + # + # 1/1 c<1>/1 + # + # It will decide that those two property sets conflict, because they both specify + # a value for 'b' and will not try building "1 ", but rather two + # different property sets. This is a topic for future fixing, maybe. + if these_features & seen_features: + + (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features) + return (inner_result, inner_seen + these_features) + + else: + + result = [] + (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features | these_features) + for inner in inner_result: + result.append(properties + inner) + + if inner_seen & these_features: + # Some of elements in property_sets[1:] conflict with elements of property_sets[0], + # Try again, this time omitting elements of property_sets[0] + (inner_result2, inner_seen2) = __x_product_aux(property_sets[1:], seen_features) + result.extend(inner_result2) + + return (result, inner_seen + these_features) + + def looks_like_implicit_value(v): """Returns true if 'v' is either implicit value, or diff --git a/v2/build/errors.py b/v2/build/errors.py index a84d0cfb7..83b39e982 100644 --- a/v2/build/errors.py +++ b/v2/build/errors.py @@ -20,7 +20,7 @@ import traceback import sys def format(message, prefix=""): - parts = message.split("\n") + parts = str(message).split("\n") return "\n".join(prefix+p for p in parts) @@ -60,7 +60,10 @@ class ExceptionWithUserContext(Exception): def report(self): print "error:", self.args[0] if self.original_exception_: - print format(self.original_exception_.args[0], " ") + try: + print format(self.original_exception_.args[0], " ") + except: + print format(str(self.original_exception_), " ") print print " error context (most recent first):" for c in self.context_[::-1]: diff --git a/v2/build/feature.py b/v2/build/feature.py index 061bb178d..852c108b4 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -14,7 +14,8 @@ import re -from b2.util import set, utility, bjam_signature +from b2.util import utility, bjam_signature +import b2.util.set from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, to_seq from b2.exceptions import * @@ -22,16 +23,73 @@ __re_split_subfeatures = re.compile ('<(.*):(.*)>') __re_no_hyphen = re.compile ('^([^:]+)$') __re_slash_or_backslash = re.compile (r'[\\/]') +class Feature(object): + + # Map from string attribute names to integers bit flags. + # This will be initialized after declaration of the class. + _attribute_name_to_integer = {} + + def __init__(self, name, values, attributes): + self._name = name + self._values = values + self._attributes = 0 + for a in attributes: + self._attributes = self._attributes | Feature._attribute_name_to_integer[a] + self._attributes_string_list = attributes + self._subfeatures = [] + self._parent = None + + def name(self): + return self._name + + def values(self): + return self._values + + def add_values(self, values): + self._values.extend(values) + + def attributes(self): + return self._attributes + + def set_default(self, value): + self._default = value + + def default(self): + return self._default + + # FIXME: remove when we fully move to using classes for features/properties + def attributes_string_list(self): + return self._attributes_string_list + + def subfeatures(self): + return self._subfeatures + + def add_subfeature(self, name): + self._subfeatures.append(name) + + def parent(self): + """For subfeatures, return pair of (parent_feature, value). + + Value may be None if this subfeature is not specific to any + value of the parent feature. + """ + + def set_parent(self, feature, value): + self._parent = (feature, value) + + def __str__(self): + return self._name + + def reset (): """ Clear the module state. This is mainly for testing purposes. """ global __all_attributes, __all_features, __implicit_features, __composite_properties - global __features_with_attributes, __subfeature_value_to_name, __all_top_features, __free_features + global __features_with_attributes, __subfeature_from_value, __all_top_features, __free_features global __all_subfeatures # The list with all attribute names. __all_attributes = [ 'implicit', - 'executed', 'composite', 'optional', 'symmetric', @@ -44,12 +102,17 @@ def reset (): 'subfeature', 'order-sensitive' ] + i = 1 + for a in __all_attributes: + setattr(Feature, a.upper(), i) + Feature._attribute_name_to_integer[a] = i + def probe(self, flag=i): + return getattr(self, "_attributes") & flag + setattr(Feature, a.replace("-", "_"), probe) + i = i << 1 - # A map containing all features. The key is the gristed feature name. The value is a map with: - # 'values': [], - # 'attributes': [], - # 'subfeatures': [], - # 'default': None + # A map containing all features. The key is the feature name. + # The value is an instance of Feature class. __all_features = {} # All non-subfeatures. @@ -58,8 +121,8 @@ def reset (): # Maps valus to the corresponding implicit feature __implicit_features = {} - # A map containing all composite properties. The key is the name of the property. The value is a map with: - # 'components': [] + # A map containing all composite properties. The key is a Property instance, + # and the value is a list of Property instances __composite_properties = {} __features_with_attributes = {} @@ -67,7 +130,7 @@ def reset (): __features_with_attributes [attribute] = [] # Maps a value to the corresponding subfeature name. - __subfeature_value_to_name = {} + __subfeature_from_value = {} # All free features __free_features = [] @@ -81,6 +144,13 @@ def enumerate (): """ return __all_features.iteritems () +def get(name): + """Return the Feature instance for the specified name. + + Throws if no feature by such name exists + """ + return __all_features[name] + # FIXME: prepare-test/finish-test? @bjam_signature((["name"], ["values", "*"], ["attributes", "*"])) @@ -90,27 +160,22 @@ def feature (name, values, attributes = []): values: a sequence of the allowable values - may be extended later with feature.extend attributes: a sequence of the feature's attributes (e.g. implicit, free, propagated, ...) """ - name = add_grist (name) - __validate_feature_attributes (name, attributes) - feature = { - 'values': [], - 'attributes': attributes, - 'subfeatures': [], - 'default': None - } - __all_features [name] = feature - - feature ['attributes'] = attributes - + feature = Feature(name, [], attributes) + __all_features[name] = feature + # Temporary measure while we have not fully moved from 'gristed strings' + __all_features["<" + name + ">"] = feature + for attribute in attributes: __features_with_attributes [attribute].append (name) + + name = add_grist(name) if 'subfeature' in attributes: __all_subfeatures.append(name) else: - __all_top_features.append(name) + __all_top_features.append(feature) extend (name, values) @@ -118,47 +183,41 @@ def feature (name, values, attributes = []): if 'free' in attributes: __free_features.append (name) + return feature + +@bjam_signature((["feature"], ["value"])) def set_default (feature, value): """ Sets the default value of the given feature, overriding any previous default. feature: the name of the feature value: the default value to assign """ - - if isinstance(feature, list): - feature = feature[0] - - feature = add_grist (feature) - f = __all_features [feature] - attributes = f['attributes'] + f = __all_features[feature] + attributes = f.attributes() bad_attribute = None - if "free" in attributes: + if attributes & Feature.FREE: bad_attribute = "free" - elif "optional" in attributes: + elif attributes & Feature.OPTIONAL: bad_attribute = "optional" if bad_attribute: - raise InvalidValue ("%s property %s cannot have a default" % (bad_attribute, feature)) + raise InvalidValue ("%s property %s cannot have a default" % (bad_attribute, feature.name())) - if isinstance(value, list): - value = value[0] - - values = f['values'] - if not value in values: + if not value in f.values(): raise InvalidValue ("The specified default value, '%s' is invalid.\n" % value + "allowed values are: %s" % values) - f ['default'] = value + f.set_default(value) -def defaults (features): +def defaults(features): """ Returns the default property values for the given features. """ + # FIXME: should merge feature and property modules. + import property + result = [] for f in features: - attributes = __all_features [f]['attributes'] - if not 'free' in attributes and not 'optional' in attributes: - defaults = __all_features [f]['default'] - if defaults: - result.append (replace_grist (defaults, f)) + if not f.free() and not f.optional() and f.default(): + result.append(property.Property(f, f.default())) return result @@ -175,20 +234,20 @@ def valid (names): def attributes (feature): """ Returns the attributes of the given feature. """ - return __all_features [feature]['attributes'] + return __all_features[feature].attributes_string_list() def values (feature): """ Return the values of the given feature. """ validate_feature (feature) - return __all_features [feature]['values'] + return __all_features[feature].values() def is_implicit_value (value_string): """ Returns true iff 'value_string' is a value_string of an implicit feature. """ v = value_string.split('-') - + if not __implicit_features.has_key(v[0]): return False @@ -211,15 +270,15 @@ def implied_feature (implicit_value): return __implicit_features[components[0]] def __find_implied_subfeature (feature, subvalue, value_string): - feature = add_grist (feature) - if value_string == None: value_string = '' + + #if value_string == None: value_string = '' - if not __subfeature_value_to_name.has_key (feature) \ - or not __subfeature_value_to_name [feature].has_key (value_string) \ - or not __subfeature_value_to_name [feature][value_string].has_key (subvalue): + if not __subfeature_from_value.has_key(feature) \ + or not __subfeature_from_value[feature].has_key(value_string) \ + or not __subfeature_from_value[feature][value_string].has_key (subvalue): return None - return __subfeature_value_to_name[feature][value_string][subvalue] + return __subfeature_from_value[feature][value_string][subvalue] # Given a feature and a value of one of its subfeatures, find the name # of the subfeature. If value-string is supplied, looks for implied @@ -238,9 +297,10 @@ def implied_subfeature (feature, subvalue, value_string): def validate_feature (name): """ Checks if all name is a valid feature. Otherwise, raises an exception. """ - x = valid (name) - if not x: + if not __all_features.has_key(name): raise InvalidFeature ("'%s' is not a valid feature name" % name) + else: + return __all_features[name] def valid (names): """ Returns true iff all elements of names are valid features. @@ -252,7 +312,8 @@ def valid (names): else: return [ valid_one (name) for name in names ] -def __expand_subfeatures_aux (feature, value, dont_validate = False): +# Uses Property +def __expand_subfeatures_aux (property, dont_validate = False): """ Helper for expand_subfeatures. Given a feature and value, or just a value corresponding to an implicit feature, returns a property set consisting of all component @@ -267,20 +328,18 @@ def __expand_subfeatures_aux (feature, value, dont_validate = False): value: The value of the feature. dont_validate: If True, no validation of value string will be done. """ - if not feature: - feature = implied_feature(value) - else: - validate_feature(feature) - + f = property.feature() + v = property.value() if not dont_validate: - validate_value_string(feature, value) - - components = value.split ("-") - - # get the top-level feature's value - value = replace_grist(components[0], '') + validate_value_string(f, v) - result = [ replace_grist(components[0], feature) ] + components = v.split ("-") + + v = components[0] + + import property + + result = [property.Property(f, components[0])] subvalues = components[1:] @@ -288,17 +347,13 @@ def __expand_subfeatures_aux (feature, value, dont_validate = False): subvalue = subvalues [0] # pop the head off of subvalues subvalues = subvalues [1:] - subfeature = __find_implied_subfeature (feature, subvalue, value) + subfeature = __find_implied_subfeature (f, subvalue, v) # If no subfeature was found, reconstitute the value string and use that if not subfeature: - result = '-'.join(components) - result = replace_grist (result, feature) - return [result] + return [property.Property(f, '-'.join(components))] - f = ungrist (feature) - # FIXME: why grist includes '<>'? - result.append (replace_grist (subvalue, '<' + f + '-' + subfeature + '>')) + result.append(property.Property(subfeature, subvalue)) return result @@ -321,12 +376,11 @@ def expand_subfeatures (properties, dont_validate = False): """ result = [] for p in properties: - p_grist = get_grist (p) # Don't expand subfeatures in subfeatures - if ':' in p_grist: + if p.feature().subfeature(): result.append (p) else: - result.extend (__expand_subfeatures_aux (p_grist, replace_grist (p, ''), dont_validate)) + result.extend(__expand_subfeatures_aux (p, dont_validate)) return result @@ -356,42 +410,41 @@ def extend (name, values): name = add_grist (name) __validate_feature (name) feature = __all_features [name] - - if 'implicit' in feature ['attributes']: + + if feature.implicit(): for v in values: - if __implicit_features.has_key (v): + if __implicit_features.has_key(v): raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) __implicit_features[v] = name - if len (feature ['values']) == 0 and len (values) > 0: + if len (feature.values()) == 0 and len (values) > 0: # This is the first value specified for this feature, # take it as default value - feature ['default'] = values[0] + feature.set_default(values[0]) - feature['values'].extend (values) + feature.add_values(values) -def validate_value_string (feature, value_string): +def validate_value_string (f, value_string): """ Checks that value-string is a valid value-string for the given feature. """ - f = __all_features [feature] - if 'free' in f ['attributes'] or value_string in f ['values']: + if f.free() or value_string in f.values(): return values = [value_string] - if f['subfeatures']: - if not value_string in f['subfeatures']: + if f.subfeatures(): + if not value_string in f.subfeatures(): values = value_string.split('-') # An empty value is allowed for optional features - if not values[0] in f['values'] and \ - (values[0] or not 'optional' in f['attributes']): - raise InvalidValue ("'%s' is not a known value of feature '%s'\nlegal values: '%s'" % (values [0], feature, f ['values'])) + if not values[0] in f.values() and \ + (values[0] or not f.optional()): + raise InvalidValue ("'%s' is not a known value of feature '%s'\nlegal values: '%s'" % (values [0], feature, f.values())) for v in values [1:]: # this will validate any subfeature values in value-string - implied_subfeature(feature, v, values[0]) + implied_subfeature(f, v, values[0]) """ Extends the given subfeature with the subvalues. If the optional @@ -411,19 +464,28 @@ def validate_value_string (feature, value_string): subvalues: The additional values of the subfeature being defined. """ -def extend_subfeature (feature, value_string, subfeature, subvalues): - feature = add_grist (feature) - validate_feature (feature) +def extend_subfeature (feature_name, value_string, subfeature_name, subvalues): + feature = validate_feature(feature_name) + if value_string: - validate_value_string (feature, value_string) + validate_value_string(feature, value_string) - subfeature_name = __get_subfeature_name (subfeature, value_string) + subfeature_name = feature_name + '-' + __get_subfeature_name (subfeature_name, value_string) - f = ungrist (feature) - extend (f + '-' + subfeature_name, subvalues) ; + extend(subfeature_name, subvalues) ; + subfeature = __all_features[subfeature_name] + + if value_string == None: value_string = '' - __add_to_subfeature_value_to_name_map (feature, value_string, subfeature_name, subvalues) + if not __subfeature_from_value.has_key(feature): + __subfeature_from_value [feature] = {} + + if not __subfeature_from_value[feature].has_key(value_string): + __subfeature_from_value [feature][value_string] = {} + + for subvalue in subvalues: + __subfeature_from_value [feature][value_string][subvalue] = subfeature def subfeature (feature_name, value_string, subfeature, subvalues, attributes = []): """ Declares a subfeature. @@ -435,50 +497,59 @@ def subfeature (feature_name, value_string, subfeature, subvalues, attributes = subvalues: The allowed values of this subfeature. attributes: The attributes of the subfeature. """ - feature_name = add_grist (feature_name) - validate_feature (feature_name) + parent_feature = validate_feature (feature_name) # Add grist to the subfeature name if a value-string was supplied subfeature_name = __get_subfeature_name (subfeature, value_string) - if subfeature_name in __all_features [feature_name]['subfeatures']: + if subfeature_name in __all_features[feature_name].subfeatures(): message = "'%s' already declared as a subfeature of '%s'" % (subfeature, feature_name) message += " specific to '%s'" % value_string raise BaseException (message) - __all_features [feature_name]['subfeatures'].append (subfeature_name) - # First declare the subfeature as a feature in its own right - f = ungrist (feature_name) - feature (f + '-' + subfeature_name, subvalues, attributes + ['subfeature']) + f = feature (feature_name + '-' + subfeature_name, subvalues, attributes + ['subfeature']) + f.set_parent(parent_feature, value_string) + + parent_feature.add_subfeature(f) # Now make sure the subfeature values are known. extend_subfeature (feature_name, value_string, subfeature, subvalues) -def compose (composite_property, component_properties): + +def compose (composite_property_s, component_properties_s): """ Sets the components of the given composite property. + + All paremeters are value strings """ - component_properties = to_seq (component_properties) + import property - feature = get_grist (composite_property) - if not 'composite' in attributes (feature): - raise BaseException ("'%s' is not a composite feature" % feature) + component_properties_s = to_seq (component_properties_s) + composite_property = property.create_from_string(composite_property_s) + f = composite_property.feature() - if __composite_properties.has_key (composite_property): - raise BaseException ('components of "%s" already set: %s' % (composite_property, str (__composite_properties [composite_property]['components']))) + if len(component_properties_s) > 0 and isinstance(component_properties_s[0], property.Property): + component_properties = component_properties_s + else: + component_properties = [property.create_from_string(p) for p in component_properties_s] + + if not f.composite(): + raise BaseException ("'%s' is not a composite feature" % f) + + if __composite_properties.has_key(property): + raise BaseException ('components of "%s" already set: %s' % (composite_property, str (__composite_properties[composite_property]))) if composite_property in component_properties: raise BaseException ('composite property "%s" cannot have itself as a component' % composite_property) - entry = { 'components': component_properties } - __composite_properties [composite_property] = entry + __composite_properties[composite_property] = component_properties -def expand_composite (property): +def expand_composite(property): result = [ property ] - if __composite_properties.has_key (property): - for p in __composite_properties [property]['components']: - result.extend (expand_composite (p)) + if __composite_properties.has_key(property): + for p in __composite_properties[property]: + result.extend(expand_composite(p)) return result @@ -501,68 +572,66 @@ def expand_composites (properties): """ Expand all composite properties in the set so that all components are explicitly expressed. """ - explicit_features = get_grist (properties) + explicit_features = set(p.feature() for p in properties) result = [] # now expand composite features for p in properties: - expanded = expand_composite (p) + expanded = expand_composite(p) for x in expanded: if not x in result: - f = get_grist (x) + f = x.feature() - if f in __free_features: + if f.free(): result.append (x) elif not x in properties: # x is the result of expansion if not f in explicit_features: # not explicitly-specified - if f in get_grist (result): - raise FeatureConflict ("expansions of composite features result in " - "conflicting values for '%s'\nvalues: '%s'\none contributing composite property was '%s'" % (f, - get_values (f, result) + [replace_grist (x, '')], p)) + if any(r.feature() == f for r in result): + raise FeatureConflict( + "expansions of composite features result in " + "conflicting values for '%s'\nvalues: '%s'\none contributing composite property was '%s'" % + (f.name(), [r.value() for r in result if r.feature() == f] + [x.value()], p)) else: result.append (x) - elif f in get_grist (result): + elif any(r.feature() == f for r in result): raise FeatureConflict ("explicitly-specified values of non-free feature '%s' conflict\n" "existing values: '%s'\nvalue from expanding '%s': '%s'" % (f, - get_values (f, properties), p, replace_grist (x, ''))) + [r.value() for r in result if r.feature() == f], p, x.value())) else: result.append (x) return result +# Uses Property def is_subfeature_of (parent_property, f): """ Return true iff f is an ordinary subfeature of the parent_property's feature, or if f is a subfeature of the parent_property's feature specific to the parent_property's value. """ - if not valid (f) or not 'subfeature' in __all_features [f]['attributes']: + if not f.subfeature(): return False - specific_subfeature = __re_split_subfeatures.match (f) + p = f.parent() + if not p: + return False - if specific_subfeature: - # The feature has the form - # , - # e.g. - feature_value = split_top_feature(specific_subfeature.group(1)) - if replace_grist (feature_value [1], '<' + feature_value [0] + '>') == parent_property: - return True - else: - # The feature has the form , - # e.g. - top_sub = split_top_feature (ungrist (f)) + parent_feature = p[0] + parent_value = p[1] - if top_sub [1] and add_grist (top_sub [0]) == get_grist (parent_property): - return True + if parent_feature != parent_property.feature(): + return False - return False + if parent_value and parent_value != parent_property.value(): + return False + + return True def __is_subproperty_of (parent_property, p): """ As is_subfeature_of, for subproperties. """ - return is_subfeature_of (parent_property, get_grist (p)) + return is_subfeature_of (parent_property, p.feature()) # Returns true iff the subvalue is valid for the feature. When the @@ -573,24 +642,21 @@ def is_subvalue(feature, value_string, subfeature, subvalue): if not value_string: value_string = '' - if not __subfeature_value_to_name.has_key(feature): + if not __subfeature_from_value.has_key(feature): return False - if not __subfeature_value_to_name[feature].has_key(value_string): + if not __subfeature_from_value[feature].has_key(value_string): return False - if not __subfeature_value_to_name[feature][value_string].has_key(subvalue): + if not __subfeature_from_value[feature][value_string].has_key(subvalue): return False - if __subfeature_value_to_name[feature][value_string][subvalue]\ + if __subfeature_from_value[feature][value_string][subvalue]\ != subfeature: return False return True - - - def implied_subfeature (feature, subvalue, value_string): result = __find_implied_subfeature (feature, subvalue, value_string) if not result: @@ -599,6 +665,7 @@ def implied_subfeature (feature, subvalue, value_string): return result +# Uses Property def expand (properties): """ Given a property set which may consist of composite and implicit properties and combined subfeature values, returns an expanded, @@ -610,36 +677,10 @@ def expand (properties): two values of a given non-free feature are directly expressed in the input, an error is issued. """ - expanded = expand_subfeatures (properties) + expanded = expand_subfeatures(properties) return expand_composites (expanded) - -def split_top_feature (feature_plus): - """ Given an ungristed string, finds the longest prefix which is a - top-level feature name followed by a dash, and return a pair - consisting of the parts before and after that dash. More - interesting than a simple split because feature names can contain - dashes. - """ - e = feature_plus.split ('-') - f = e [0] - - v = None - while e: - if add_grist (f) in __all_top_features: - if len (e) > 1: - after = '-'.join (e [1:]) - else: - after = '' - - v = (f, after) - - e = e [1:] - f = f + '-' - if len (e): f += e [0] - - return v - +# Accepts list of Property objects def add_defaults (properties): """ Given a set of properties, add default values for features not represented in the set. @@ -658,35 +699,28 @@ def add_defaults (properties): and that's kind of strange. """ - result = [ x for x in properties ] + result = [x for x in properties] - for v in replace_grist (properties, ''): - if v in properties: - raise BaseException ("'add_defaults' requires explicitly specified features, but '%s' appears to be the value of an un-expanded implicit feature" % v) - - # We don't add default for elements with ":" inside. This catches: - # 1. Conditional properties --- we don't want debug:DEBUG - # to be takes as specified value for - # 2. Free properties with ":" in values. We don't care, since free properties - # don't have defaults. - xproperties = [ property for property in properties if __re_no_hyphen.match (property) ] - missing_top = set.difference (__all_top_features, get_grist (xproperties)) - more = defaults (missing_top) - result += more - xproperties += more - - # Add defaults for subfeatures of features which are present - for p in xproperties: - gp = get_grist (p) - s = [] - if __all_features.has_key (gp): - s = __all_features [gp]['subfeatures'] - f = ungrist (gp) + handled_features = set() + for p in properties: + # We don't add default for conditional properties. We don't want + # debug:DEBUG to be takes as specified value for + if not p.condition(): + handled_features.add(p.feature()) - xbase = ['<%s-%s>' % (f, xs) for xs in s] - - missing_subs = set.difference (xbase, get_grist (result)) - result += defaults (__select_subfeatures (p, missing_subs)) + missing_top = [f for f in __all_top_features if not f in handled_features] + more = defaults(missing_top) + result.extend(more) + for p in more: + handled_features.add(p.feature()) + + # Add defaults for subfeatures of features which are present + for p in result[:]: + s = p.feature().subfeatures() + more = defaults([s for s in p.feature().subfeatures() if not s in handled_features]) + for p in more: + handled_features.add(p.feature()) + result.extend(more) return result @@ -699,47 +733,35 @@ def minimize (properties): grist, and sub-property values will be expressed as elements joined to the corresponding main property. """ -# FXIME: the code below was in the original feature.jam file, however 'p' is not defined. -# # Precondition checking -# local implicits = [ set.intersection $(p:G=) : $(p:G) ] ; -# if $(implicits) -# { -# error minimize requires an expanded property set, but \"$(implicits[1])\" -# appears to be the value of an un-expanded implicit feature ; -# } - + # remove properties implied by composite features components = [] for property in properties: if __composite_properties.has_key (property): - components.extend (__composite_properties [property]['components']) - - x = set.difference (properties, components) + components.extend(__composite_properties[property]) + properties = b2.util.set.difference (properties, components) # handle subfeatures and implicit features - x = __move_subfeatures_to_the_end (x) + + # move subfeatures to the end of the list + properties = [p for p in properties if not p.feature().subfeature()] +\ + [p for p in properties if p.feature().subfeature()] result = [] - while x: - fullp = x [0] - p = fullp - f = get_grist (p) - v = replace_grist (p, '') + while properties: + p = properties[0] + f = p.feature() - # eliminate features in implicit properties. - if 'implicit' in __all_features [f]['attributes']: - p = v - # locate all subproperties of $(x[1]) in the property set - subproperties = __select_subproperties (fullp, x) + subproperties = __select_subproperties (p, properties) if subproperties: # reconstitute the joined property name subproperties.sort () - joined = p + '-' + '-'.join (replace_grist (subproperties, '')) - result.append (joined) + joined = Property(p.feature(), p.value() + '-' + '-'.join ([sp.value() for sp in subproperties])) + result.append(joined) - x = set.difference (x [1:], subproperties) + properties = b2.util.set.difference(properties[1:], subproperties) else: # eliminate properties whose value is equal to feature's @@ -750,11 +772,14 @@ def minimize (properties): # have been eliminated, any remaining property whose # feature is the same as a component of a composite in the # set must have a non-redundant value. - if [fullp] != defaults ([f]) or 'symmetric' in attributes (f)\ - or get_grist (fullp) in get_grist (components): + if p.value() != f.default() or f.symmetric(): result.append (p) + #\ + #or get_grist (fullp) in get_grist (components): + # FIXME: restore above + - x = x [1:] + properties = properties[1:] return result @@ -809,7 +834,7 @@ def compress_subproperties (properties): if not pg: raise BaseException ("Gristed variable exppected. Got '%s'." % p) - if not 'subfeature' in __all_features [pg]['attributes']: + if not __all_features [pg].subfeature(): subs = __select_subproperties (p, properties) matched_subs.extend (subs) @@ -823,7 +848,7 @@ def compress_subproperties (properties): all_subs.append (p) # TODO: this variables are used just for debugging. What's the overhead? - assert (set.equal (all_subs, matched_subs)) + assert (b2.util.set.equal (all_subs, matched_subs)) return result @@ -833,22 +858,6 @@ def compress_subproperties (properties): def __select_subproperties (parent_property, properties): return [ x for x in properties if __is_subproperty_of (parent_property, x) ] -def __move_subfeatures_to_the_end (properties): - """ Helper for minimize, below - returns the list with - the same properties, but where all subfeatures - are in the end of the list - """ - x1 = [] - x2 = [] - for p in properties: - if 'subfeature' in __all_features [get_grist (p)]['attributes']: - x2.append (p) - - else: - x1.append (p) - - return x1 + x2 - def __get_subfeature_name (subfeature, value_string): if value_string == None: prefix = '' @@ -861,7 +870,7 @@ def __get_subfeature_name (subfeature, value_string): def __validate_feature_attributes (name, attributes): for attribute in attributes: if not attribute in __all_attributes: - raise InvalidAttribute ("unknown attributes: '%s' in feature declaration: '%s'" % (str (set.difference (attributes, __all_attributes)), name)) + raise InvalidAttribute ("unknown attributes: '%s' in feature declaration: '%s'" % (str (b2.util.set.difference (attributes, __all_attributes)), name)) if name in __all_features: raise AlreadyDefined ("feature '%s' already defined" % name) @@ -877,20 +886,6 @@ def __validate_feature (feature): if not __all_features.has_key (feature): raise BaseException ('unknown feature "%s"' % feature) -def __add_to_subfeature_value_to_name_map (feature, value_string, subfeature_name, subvalues): - # provide a way to get from the given feature or property and - # subfeature value to the subfeature name. - if value_string == None: value_string = '' - - if not __subfeature_value_to_name.has_key (feature): - __subfeature_value_to_name [feature] = {} - - if not __subfeature_value_to_name [feature].has_key (value_string): - __subfeature_value_to_name [feature][value_string] = {} - - for subvalue in subvalues: - __subfeature_value_to_name [feature][value_string][subvalue] = subfeature_name - def __select_subfeatures (parent_property, features): """ Given a property, return the subset of features consisting of all diff --git a/v2/build/property.py b/v2/build/property.py index 490815ea6..9d03d683d 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -10,20 +10,90 @@ import re from b2.util.utility import * from b2.build import feature -from b2.util import sequence, set +from b2.util import sequence +import b2.util.set from b2.manager import get_manager __re_two_ampersands = re.compile ('&&') __re_comma = re.compile (',') __re_split_condition = re.compile ('(.*):(<.*)') -__re_toolset_feature = re.compile ('^(|)') -__re_os_feature = re.compile ('^()') __re_split_conditional = re.compile (r'(.+):<(.+)') __re_colon = re.compile (':') __re_has_condition = re.compile (r':<') __re_separate_condition_and_property = re.compile (r'(.*):(<.*)') __re_indirect_rule = re.compile("^([^%]*)%([^%]+)$") +class Property(object): + + __slots__ = ('_feature', '_value', '_condition') + + def __init__(self, feature, value, condition = []): + assert(feature.free() or value.find(':') == -1) + self._feature = feature + self._value = value + self._condition = condition + + + def feature(self): + return self._feature + + def value(self): + return self._value + + def condition(self): + return self._condition + + def to_raw(self): + # FIXME: include condition! + return "<" + self._feature.name() + ">" + self._value + + def __str__(self): + return self.to_raw() + + def __hash__(self): + # FIXME: consider if this class should be value-is-identity one + return hash((self._feature, self._value, tuple(self._condition))) + + def __cmp__(self, other): + return cmp((self._feature, self._value, self._condition), + (other._feature, other._value, other._condition)) + + +def create_from_string(s, allow_condition = False): + + condition = [] + if __re_has_condition.search(s): + + if not allow_condition: + raise BaseException("Conditional property is not allowed in this context") + + m = __re_separate_condition_and_property.match(s) + condition = m.group(1) + s = m.group(2) + + # FIXME: break dependency cycle + from b2.manager import get_manager + + feature_name = get_grist(s) + if not feature_name: + if feature.is_implicit_value(s): + f = feature.implied_feature(s) + value = s + else: + raise get_manager().errors()("Invalid property '%s' -- unknown feature" % s) + else: + f = feature.get(feature_name) + + value = get_value(s) + if not value: + get_manager().errors()("Invalid property '%s' -- no value specified" % s) + + + if condition: + condition = [create_from_string(x) for x in condition.split(',')] + + return Property(f, value, condition) + def reset (): """ Clear the module state. This is mainly for testing purposes. """ @@ -64,51 +134,18 @@ def path_order (x, y): else: return 0 -def abbreviate_dashed(string): - # FIXME: string.abbreviate? - return [string.abbreviate(part) for part in string.split('-')].join('-') - def identify(string): return string -# FIXME: --abbreviate-paths - -def as_path (properties): - """ Returns a path which represents the given expanded property set. - """ - key = '-'.join (properties) - - if not __results.has_key (key): - # trim redundancy - properties = feature.minimize (properties) - - # sort according to path_order - properties.sort (path_order) - - components = [] - for p in properties: - pg = get_grist (p) - # FIXME: abbrev? - if pg: - f = ungrist (pg) - components.append (f + '-' + replace_grist (p, '')) - - else: - components.append (p) - - __results [key] = '/'.join (components) - - return __results [key] - +# Uses Property def refine (properties, requirements): """ Refines 'properties' by overriding any non-free properties for which a different value is specified in 'requirements'. Conditional requirements are just added without modification. Returns the resulting list of properties. """ - # The result has no duplicates, so we store it in a map - # TODO: use a set from Python 2.4? - result = {} + # The result has no duplicates, so we store it in a set + result = set() # Records all requirements. required = {} @@ -117,31 +154,23 @@ def refine (properties, requirements): # Record them so that we can handle 'properties'. for r in requirements: # Don't consider conditional requirements. - if not is_conditional (r): - # Note: cannot use local here, so take an ugly name - required [get_grist (r)] = replace_grist (r, '') + if r.condition(): + required[r.feature()] = r for p in properties: # Skip conditional properties - if is_conditional (p): - result [p] = None + if p.condition(): + result.add(p) # No processing for free properties - elif 'free' in feature.attributes (get_grist (p)): - result [p] = None + elif p.feature().free(): + result.add(p) else: - if required.has_key (get_grist (p)): - required_value = required [get_grist (p)] - - value = replace_grist (p, '') - - if value != required_value: - result [replace_grist (required_value, get_grist (p))] = None - else: - result [p] = None + if required.has_key(p.feature()): + result.add(required[p.feature()]) else: - result [p] = None + result.add(p) - return result.keys () + requirements + return sequence.unique(list(result) + requirements) def translate_paths (properties, path): """ Interpret all path properties in 'properties' as relative to 'path' @@ -168,7 +197,7 @@ def translate_paths (properties, path): result.append (condition + tp) else: - result.append (condition + p) + result.append (condition + ":" + p) return result @@ -205,7 +234,7 @@ def translate_indirect(specification, context_module): result.append(get_grist(px) + "@" + m) else: - result.append(p) + result.append(px) return result @@ -224,38 +253,20 @@ def expand_subfeatures_in_conditions (properties): result = [] for p in properties: - s = __re_split_condition.match (p) - if not s: - result.append (p) + if not p.condition(): + result.append(p) - else: - condition = s.group (1) - - # Condition might include several elements - condition = __re_comma.split (condition) - - value = s.group (2) - - e = [] - for c in condition: - - cg = get_grist (c) - if __re_toolset_feature.match (cg) or __re_os_feature.match (cg): - # It common that condition includes a toolset which - # was never defined, or mentiones subfeatures which - # were never defined. In that case, validation will - # only produce an spirious error, so don't validate. - e.append (feature.expand_subfeatures (c, True)) - - else: - e.append (feature.expand_subfeatures (c)) - - if e == condition: - result.append (p) + for c in p.condition(): + if c.feature().name().startswith("toolset") or c.feature().name() == "os": + # It common that condition includes a toolset which + # was never defined, or mentiones subfeatures which + # were never defined. In that case, validation will + # only produce an spirious error, so don't validate. + result.extend(feature.expand_subfeatures ([c], True)) else: - result.append (','.join(e) + ':' + value) + result.extend(feature.expand_subfeatures([c])) return result @@ -277,6 +288,7 @@ def make (specification): return result +# FIXME: this should go def split_conditional (property): """ If 'property' is conditional property, returns condition and the property, e.g @@ -291,6 +303,7 @@ def split_conditional (property): return None +# FIXME: this should go def is_conditional (property): """ Returns True if a property is conditional. """ @@ -311,8 +324,7 @@ def select (features, properties): def validate_property_sets (sets): for s in sets: - validate(feature.split(s)) - + validate(s.all()) def evaluate_conditionals_in_context (properties, context): """ Removes all conditional properties which conditions are not met @@ -338,41 +350,11 @@ def evaluate_conditionals_in_context (properties, context): conditions = s.group (1).split (',') # Evaluate condition - if set.contains (c, context): + if b2.util.set.contains (conditions, context): result.append (s.group (2)) return result -def expand_subfeatures_in_conditions(properties): - - result = [] - for p in properties: - - s = __re_separate_condition_and_property.match(p) - if not s: - result.append(p) - else: - condition = s.group(1) - # Condition might include several elements - condition = condition.split(",") - value = s.group(2) - - e = [] - for c in condition: - # It common that condition includes a toolset which - # was never defined, or mentiones subfeatures which - # were never defined. In that case, validation will - # only produce an spirious error, so prevent - # validation by passing 'true' as second parameter. - e.extend(feature.expand_subfeatures(c, dont_validate=True)) - - if e == condition: - result.append(p) - else: - individual_subfeatures = set.difference(e, condition) - result.append(",".join(individual_subfeatures) + ":" + value) - - return result def change (properties, feature, value = None): """ Returns a modified version of properties with all values of the @@ -402,30 +384,8 @@ def __validate1 (property): """ msg = None - f = get_grist (property) - if f: - value = get_value (property) - - if not feature.valid (f): - f = ungrist (get_grist (property)) # Ungrist for better error messages - msg = "Unknown feature '%s'" % f - - elif value and not 'free' in feature.attributes (f): - feature.validate_value_string (f, value) - - elif not value: - f = ungrist (get_grist (property)) # Ungrist for better error messages - msg = "No value specified for feature '%s'" % f - - else: - f = feature.implied_feature (property) - feature.validate_value_string (f, property) - - if msg: - # FIXME: don't use globals like this. Import here to - # break circular dependency. - from b2.manager import get_manager - get_manager().errors()("Invalid property '%s': %s" % (property, msg)) + if not property.feature().free(): + feature.validate_value_string (property.feature(), property.value()) ################################################################### @@ -479,7 +439,7 @@ def take(attributes, properties): properties in 'properties' that have any of 'attributes'.""" result = [] for e in properties: - if set.intersection(attributes, feature.attributes(get_grist(e))): + if b2.util.set.intersection(attributes, feature.attributes(get_grist(e))): result.append(e) return result @@ -514,6 +474,7 @@ def translate_dependencies(specification, project_id, location): return result + class PropertyMap: """ Class which maintains a property set -> string mapping. """ @@ -542,7 +503,7 @@ class PropertyMap: for i in range(0, len(self.__properties)): p = self.__properties[i] - if set.contains (p, properties): + if b2.util.set.contains (p, properties): matches.append (i) match_ranks.append(len(p)) diff --git a/v2/build/property_set.py b/v2/build/property_set.py index 5ccafd404..f404ae2cc 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -28,13 +28,20 @@ def create (raw_properties = []): """ Creates a new 'PropertySet' instance for the given raw properties, or returns an already existing one. """ - raw_properties.sort () - raw_properties = unique (raw_properties) - - key = '-'.join (raw_properties) + # FIXME: propagate to callers. + if len(raw_properties) > 0 and isinstance(raw_properties[0], property.Property): + x = raw_properties + else: + x = [property.create_from_string(ps) for ps in raw_properties] + x.sort () + x = unique (x) + + # FIXME: can we do better, e.g. by directly computing + # has value of the list? + key = tuple(x) if not __cache.has_key (key): - __cache [key] = PropertySet (raw_properties) + __cache [key] = PropertySet(x) return __cache [key] @@ -43,9 +50,10 @@ def create_with_validation (raw_properties): that all properties are valid and converting incidental properties into gristed form. """ - property.validate (raw_properties) + properties = [property.create_from_string(s) for s in raw_properties] + property.validate(properties) - return create (property.make (raw_properties)) + return create(properties) def empty (): """ Returns PropertySet with empty set of properties. @@ -56,13 +64,12 @@ def create_from_user_input(raw_properties, jamfile_module, location): """Creates a property-set from the input given by the user, in the context of 'jamfile-module' at 'location'""" - property.validate(raw_properties) - specification = property.translate_paths(raw_properties, location) specification = property.translate_indirect(specification, jamfile_module) - specification = property.expand_subfeatures_in_conditions(specification) specification = property.make(specification) - return create(specification) + properties = [property.create_from_string(s, True) for s in specification] + properties = property.expand_subfeatures_in_conditions(properties) + return create(properties) def refine_from_user_input(parent_requirements, specification, jamfile_module, @@ -126,13 +133,20 @@ class PropertySet: - several operations, like and refine and as_path are provided. They all use caching whenever possible. """ - def __init__ (self, raw_properties = []): + def __init__ (self, properties = []): - self.raw_ = raw_properties + + raw_properties = [] + for p in properties: + raw_properties.append(p.to_raw()) + + self.all_ = properties + self.all_raw_ = raw_properties self.incidental_ = [] self.free_ = [] self.base_ = [] + self.base_raw_ = [] self.dependency_ = [] self.non_dependency_ = [] self.conditional_ = [] @@ -155,6 +169,9 @@ class PropertySet: # Cache for the expanded composite properties self.composites_ = None + # Cache for property set with expanded subfeatures + self.subfeatures_ = None + # Cache for the property set containing propagated properties. self.propagated_ps_ = None @@ -178,40 +195,55 @@ class PropertySet: # A feature can be both incidental and free, # in which case we add it to incidental. if 'incidental' in att: - self.incidental_.append (p) + pass +# self.incidental_.append (p) elif 'free' in att: - self.free_.append (p) + # self.free_.append (p) + pass else: - self.base_.append (p) + self.base_raw_.append (p) if 'dependency' in att: self.dependency_.append (p) else: self.non_dependency_.append (p) - if property.is_conditional (p): - self.conditional_.append (p) - else: - self.non_conditional_.append (p) - + if 'propagated' in att: self.propagated_.append (p) if 'link_incompatible' in att: self.link_incompatible.append (p) + + for p in properties: + + if p.feature().incidental(): + self.incidental_.append(p) + elif p.feature().free(): + self.free_.append(p) + else: + self.base_.append(p) + + if p.condition(): + self.conditional_.append(p) + else: + self.non_conditional_.append(p) + + def all(self): + return self.all_ def raw (self): """ Returns the list of stored properties. """ - return self.raw_ + return self.all_raw_ def __str__(self): - return string.join(self.raw_) + return string.join(self.all_raw_) def base (self): """ Returns properties that are neither incidental nor free. """ - return self.base_ + return self.base_raw_ def free (self): """ Returns free properties which are not dependency properties. @@ -246,32 +278,37 @@ class PropertySet: def refine (self, requirements): """ Refines this set's properties using the requirements passed as an argument. """ - str_req = str (requirements) - if not self.refined_.has_key (str_req): - r = property.refine (self.raw (), requirements.raw ()) + assert isinstance(requirements, PropertySet) + if not self.refined_.has_key (requirements): + r = property.refine(self.all_, requirements.all_) - self.refined_ [str_req] = create (r) + self.refined_[requirements] = create(r) - return self.refined_ [str_req] + return self.refined_[requirements] def expand (self): if not self.expanded_: - expanded = feature.expand (self.raw_) - self.expanded_ = create (expanded) + expanded = feature.expand(self.all_) + self.expanded_ = create(expanded) return self.expanded_ def expand_componsite(self): if not self.componsites_: - self.composites_ = create(feature.expand_composires(self.raw_)) + self.composites_ = create(feature.expand_composires(self.all_raw_)) return self.composites_ + def expand_subfeature(self): + if not self.subfeatures_: + self.subfeatures_ = create(feature.expand_subfeatures(self.all_)) + return self.subfeatures_ + def evaluate_conditionals(self, context=None): if not context: context = self if not self.evaluated_.has_key(context): self.evaluated_[context] = create( - property.evaluate_conditionals_in_context(self.raw_, + property.evaluate_conditionals_in_context(self.all_raw_, context.raw())) return self.evaluated_[context] @@ -283,13 +320,37 @@ class PropertySet: def add_defaults (self): if not self.defaults_: - expanded = feature.add_defaults(self.raw_) + expanded = feature.add_defaults(self.all_) self.defaults_ = create(expanded) return self.defaults_ def as_path (self): if not self.as_path_: - self.as_path_ = property.as_path(self.base_) + + def path_order (p1, p2): + + i1 = p1.feature().implicit() + i2 = p2.feature().implicit() + + if i1 != i2: + return i2 - i1 + else: + return cmp(p1.feature().name(), p2.feature().name()) + + # trim redundancy + properties = feature.minimize(self.base_) + + # sort according to path_order + properties.sort (path_order) + + components = [] + for p in properties: + if p.feature().implicit(): + components.append(p.value()) + else: + components.append(p.feature().name() + "-" + p.value()) + + self.as_path_ = '/'.join (components) return self.as_path_ @@ -341,9 +402,9 @@ class PropertySet: """ Creates a new property set containing the properties in this one, plus the ones of the property set passed as argument. """ - if not self.added_.has_key (str (ps)): - self.added_ [str (ps)] = create (self.raw_ + ps.raw ()) - return self.added_ [str (ps)] + if not self.added_.has_key(ps): + self.added_[ps] = create(self.all_ + ps.all()) + return self.added_[ps] def add_raw (self, properties): """ Creates a new property set containing the properties in this one, @@ -353,16 +414,15 @@ class PropertySet: def get (self, feature): - """ Returns all values of 'feature'. + """ Returns all properties for 'feature'. """ if not self.feature_map_: self.feature_map_ = {} - for v in self.raw_: - key = get_grist (v) - if not self.feature_map_.has_key (key): - self.feature_map_ [key] = [] - self.feature_map_ [get_grist (v)].append (replace_grist (v, '')) + for v in self.all_: + if not self.feature_map_.has_key(v.feature()): + self.feature_map_[v.feature()] = [] + self.feature_map_[v.feature()].append(v) - return self.feature_map_.get (feature, []) + return self.feature_map_.get(feature, []) diff --git a/v2/build/targets.py b/v2/build/targets.py index 2bcf8f1d0..e603a9486 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -685,7 +685,7 @@ class MainTarget (AbstractTarget): # be an indication that # build_request.expand-no-defaults is the wrong rule # to use here. - compressed = feature.compress-subproperties (raw) + compressed = feature.compress_subproperties (raw) properties = build_request.expand_no_defaults (compressed, defaults_to_apply) @@ -873,13 +873,13 @@ class BasicTarget (AbstractTarget): # without using complex algorithsm. # This gives the complex algorithm better chance of caching results. free = requirements.free () - non_free = property_set.create (requirements.base () + requirements.incidental ()) + non_free = property_set.create(requirements.base() + requirements.incidental()) - key = str (build_request) + '-' + str (non_free) - if not self.request_cache.has_key (key): - self.request_cache [key] = self.__common_properties2 (build_request, non_free) + key = (build_request, non_free) + if not self.request_cache.has_key(key): + self.request_cache[key] = self.__common_properties2 (build_request, non_free) - return self.request_cache [key].add_raw (free) + return self.request_cache[key].add_raw(free) # Given 'context' -- a set of already present properties, and 'requirements', # decide which extra properties should be applied to 'context'. @@ -909,7 +909,7 @@ class BasicTarget (AbstractTarget): unconditional = feature.expand(requirements.non_conditional()) - raw = context.raw() + raw = context.all() raw = property.refine(raw, unconditional) # We've collected properties that surely must be present in common diff --git a/v2/build/toolset.py b/v2/build/toolset.py index f952c3f6a..6c76f5512 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -11,8 +11,9 @@ """ import feature, property, generators, property_set +import b2.util.set from b2.util.utility import * -from b2.util import set, bjam_signature +from b2.util import bjam_signature __re_split_last_segment = re.compile (r'^(.+)\.([^\.])*') __re_two_ampersands = re.compile ('(&&)') @@ -67,30 +68,13 @@ reset () # FIXME: --ignore-toolset-requirements # FIXME: using -def normalize_condition (property_sets): - """ Expands subfeatures in each property set. - e.g - gcc-3.2 - will be converted to - gcc/3.2 - - TODO: does this one belong here or in feature? - """ - result = [] - for p in property_sets: - split = feature.split (p) - expanded = feature.expand_subfeatures (split) - result.append ('/'.join (expanded)) - - return result - # FIXME push-checking-for-flags-module .... # FIXME: investigate existing uses of 'hack-hack' parameter # in jam code. @bjam_signature((["rule_or_module", "variable_name", "condition", "*"], ["values", "*"])) -def flags (rule_or_module, variable_name, condition, values = []): +def flags(rule_or_module, variable_name, condition, values = []): """ Specifies the flags (variables) that must be set on targets under certain conditions, described by arguments. rule_or_module: If contains dot, should be a rule name. @@ -140,63 +124,64 @@ def flags (rule_or_module, variable_name, condition, values = []): condition = None if condition: - property.validate_property_sets (condition) - condition = normalize_condition ([condition]) + 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 = feature.expand_subfeatures(pl); + transformed.append(property_set.create(pl)) + condition = transformed + + property.validate_property_sets(condition) __add_flag (rule_or_module, variable_name, condition, values) -def set_target_variables (manager, rule_or_module, targets, properties): +def set_target_variables (manager, rule_or_module, targets, ps): """ """ - key = rule_or_module + '.' + str (properties) - settings = __stv.get (key, None) + settings = __stv.get(ps, None) if not settings: - settings = __set_target_variables_aux (manager, rule_or_module, properties) + settings = __set_target_variables_aux(manager, rule_or_module, ps) - __stv [key] = settings + __stv[ps] = settings if settings: for s in settings: for target in targets: manager.engine ().set_target_variable (target, s [0], s[1], True) -def find_property_subset (property_sets, properties): +def find_satisfied_condition(conditions, ps): """Returns the first element of 'property-sets' which is a subset of 'properties', or an empty list if no such element exists.""" - - prop_keys = get_grist(properties) - for s in property_sets: - # Handle value-less properties like '' (compare with - # 'x86'). + features = set(p.feature() for p in ps.all()) - set = feature.split(s) + for condition in conditions: - # Find the set of features that - # - have no property specified in required property set - # - are omitted in build property set - default_props = [] - for i in set: - # If $(i) is a value-less property it should match default - # value of an optional property. See the first line in the - # example below: - # - # property set properties result - # foo foo match - # foo foo foo no match - # foo foo foo no match - # foo foo foo foo match - if not (get_value(i) or get_grist(i) in prop_keys): - default_props.append(i) + found_all = True + for i in condition.all(): - # FIXME: can this be expressed in a more pythonic way? - has_all = 1 - for i in set: - if i not in (properties + default_props): - has_all = 0 - break - if has_all: - return s + found = False + if i.value(): + found = i in ps.get(i.feature()) + else: + # Handle value-less properties like '' (compare with + # 'x86'). + # If $(i) is a value-less property it should match default + # value of an optional property. See the first line in the + # example below: + # + # property set properties result + # foo foo match + # foo foo foo no match + # foo foo foo no match + # foo foo foo foo match + found = not i.feature() in features + + found_all = found_all and found + + if found_all: + return condition return None @@ -241,7 +226,7 @@ def inherit_flags(toolset, base, prohibited_properties = []): call it as needed.""" for f in __module_flags.get(base, []): - if not f.condition or set.difference(f.condition, prohibited_properties): + if not f.condition or b2.util.set.difference(f.condition, prohibited_properties): match = __re_first_group.match(f.rule) rule_ = None if match: @@ -292,7 +277,7 @@ def inherit_rules (toolset, base): ###################################################################################### # Private functions -def __set_target_variables_aux (manager, rule_or_module, properties): +def __set_target_variables_aux (manager, rule_or_module, ps): """ Given a rule name and a property set, returns a list of tuples of variables names and values, which must be set on targets for that rule/properties combination. @@ -301,12 +286,12 @@ def __set_target_variables_aux (manager, rule_or_module, properties): for f in __flags.get(rule_or_module, []): - if not f.condition or find_property_subset (f.condition, properties): + if not f.condition or find_satisfied_condition (f.condition, ps): processed = [] for v in f.values: # The value might be so needs special # treatment. - processed += __handle_flag_value (manager, v, properties) + processed += __handle_flag_value (manager, v, ps) for r in processed: result.append ((f.variable_name, r)) @@ -316,27 +301,28 @@ def __set_target_variables_aux (manager, rule_or_module, properties): if next: result.extend(__set_target_variables_aux( - manager, next.group(1), properties)) + manager, next.group(1), ps)) return result -def __handle_flag_value (manager, value, properties): +def __handle_flag_value (manager, value, ps): result = [] if get_grist (value): - matches = property.select (value, properties) - for p in matches: - att = feature.attributes (get_grist (p)) - - ungristed = replace_grist (p, '') + f = feature.get(value) + properties = ps.get(feature) + + for p in properties: - if 'dependency' in att: + value = p.value() + + if f.dependency(): # the value of a dependency feature is a target # and must be actualized # FIXME: verify that 'find' actually works, ick! - result.append (manager.targets ().find (ungristed).actualize ()) + result.append (manager.targets ().find (p.value()).actualize ()) - elif 'path' in att or 'free' in att: + elif f.path() or f.free(): values = [] # Treat features with && in the value diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index b4af3a771..c58455a87 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -755,14 +755,12 @@ class Action: self.engine_.add_dependency (actual_targets, self.actual_sources_ + self.dependency_only_sources_) - raw_properties = properties.raw () - # FIXME: check the comment below. Was self.action_name_ [1] # Action name can include additional argument to rule, which should not # be passed to 'set-target-variables' # FIXME: breaking circular dependency import toolset - toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, raw_properties) + toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties) engine = self.manager_.engine () diff --git a/v2/build_system.py b/v2/build_system.py index b4589ee72..0403d5b13 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -275,12 +275,10 @@ def main_real(): (target_ids, properties) = b2.build.build_request.from_command_line( argv[1:] + extra_build_request) + properties = [property_set.create(feature.split(ps)) for ps in properties] + if properties: expanded = b2.build.build_request.expand_no_defaults(properties) - xexpanded = [] - for e in expanded: - xexpanded.append(property_set.create(feature.split(e))) - expanded = xexpanded else: expanded = [property_set.empty()] diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index a99682f4b..ff72b4dc2 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -47,39 +47,35 @@ def variant (name, parents_or_properties, explicit_properties = []): """ parents = [] if not explicit_properties: - if get_grist (parents_or_properties [0]): - explicit_properties = parents_or_properties - - else: - parents = parents_or_properties - + explicit_properties = parents_or_properties else: parents = parents_or_properties - - # The problem is that we have to check for conflicts - # between base variants. - if len (parents) > 1: - raise BaseException ("Multiple base variants are not yet supported") - inherited = [] - # Add explicitly specified properties for parents - for p in parents: + inherited = property_set.empty() + if parents: + + # If we allow multiple parents, we'd have to to check for conflicts + # between base variants, and there was no demand for so to bother. + if len (parents) > 1: + raise BaseException ("Multiple base variants are not yet supported") + + p = parents[0] # TODO: the check may be stricter if not feature.is_implicit_value (p): raise BaseException ("Invalid base varaint '%s'" % p) - inherited += __variant_explicit_properties [p] + inherited = __variant_explicit_properties[p] - property.validate (explicit_properties) - explicit_properties = property.refine (inherited, explicit_properties) + explicit_properties = property_set.create_with_validation(explicit_properties) + explicit_properties = inherited.refine(explicit_properties) # Record explicitly specified properties for this variant # We do this after inheriting parents' properties, so that # they affect other variants, derived from this one. - __variant_explicit_properties [name] = explicit_properties + __variant_explicit_properties[name] = explicit_properties feature.extend('variant', [name]) - feature.compose (replace_grist (name, ''), explicit_properties) + feature.compose ("" + name, explicit_properties.all()) __os_names = """ amiga aix bsd cygwin darwin dos emx freebsd hpux iphone linux netbsd From 89fbab2f72e4c2d99505edda994bd7ba9c66b15a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 09:38:49 +0000 Subject: [PATCH 029/165] Fix flag setting [SVN r64287] --- v2/build/toolset.py | 6 +++--- v2/build/virtual_target.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/v2/build/toolset.py b/v2/build/toolset.py index 6c76f5512..9d4ff3425 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -310,7 +310,7 @@ def __handle_flag_value (manager, value, ps): if get_grist (value): f = feature.get(value) - properties = ps.get(feature) + properties = ps.get(f) for p in properties: @@ -329,8 +329,8 @@ def __handle_flag_value (manager, value, ps): # specially -- each &&-separated element is considered # separate value. This is needed to handle searched # libraries, which must be in specific order. - if not __re_two_ampersands.search (ungristed): - values.append (ungristed) + if not __re_two_ampersands.search(value): + values.append(value) else: values.extend(value.split ('&&')) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index c58455a87..61706ddf9 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -746,6 +746,7 @@ class Action: ps = self.properties () properties = self.adjust_properties (ps) + actual_targets = [] for i in self.targets (): From f6b618d47e818b538b75faa9922c02216ff7b4e6 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 10:52:36 +0000 Subject: [PATCH 030/165] More fixups [SVN r64290] --- v2/build/project.py | 2 +- v2/build/property.py | 60 ++++++++++++++-------------------------- v2/build/property_set.py | 15 ++++++---- v2/build/toolset.py | 17 ++++-------- v2/tools/builtin.py | 5 ++++ 5 files changed, 41 insertions(+), 58 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 0f42e500a..b1ff07c49 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -727,7 +727,7 @@ class ProjectAttributes: # FIXME: #errors.error "usage-requirements" $(specification) "have non-free properties" $(non-free) ; - t = property.translate_paths(specification, self.location) + t = property.translate_paths(property.create_from_strings(specification), self.location) existing = self.__dict__.get("usage-requirements") if existing: diff --git a/v2/build/property.py b/v2/build/property.py index 9d03d683d..9a59c61a2 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -94,6 +94,10 @@ def create_from_string(s, allow_condition = False): return Property(f, value, condition) +def create_from_strings(string_list, validate=False): + + return [create_from_string(s, validate) for s in string_list] + def reset (): """ Clear the module state. This is mainly for testing purposes. """ @@ -180,45 +184,39 @@ def translate_paths (properties, path): result = [] for p in properties: - split = split_conditional (p) - condition = '' + if p.feature().path(): + values = __re_two_ampersands.split(p.value()) + + new_value = "&&".join(os.path.join(path, v) for v in values) - if split: - condition = split [0] - p = split [1] - - if get_grist (p) and 'path' in feature.attributes (get_grist (p)): - values = __re_two_ampersands.split (forward_slashes (replace_grist (p, ""))) - - t = [os.path.join(path, v) for v in values] - t = '&&'.join (t) - tp = replace_grist (t, get_grist (p)).replace("\\", "/") - result.append (condition + tp) + if new_value != p.value(): + result.append(Property(p.feature(), new_value, p.condition())) + else: + result.append(p) else: - result.append (condition + ":" + p) + result.append (p) return result -def translate_indirect(specification, context_module): +def translate_indirect(properties, context_module): """Assumes that all feature values that start with '@' are names of rules, used in 'context-module'. Such rules can be either local to the module or global. Qualified local rules with the name of the module.""" result = [] - for px in specification: - p = get_value(px) - if p[0] == '@': + for p in properties: + if p.value()[0] == '@': v = None - m = p[1:] + m = p.value()[1:] if __re_indirect_rule.match(m): # Rule is already in indirect format # FIXME: it's not clear if this is necessary. v = m else: - if not '.' in p: + if not '.' in m: # This is unqualified rule name. The user might want # to set flags on this rule name, and toolset.flag # auto-qualifies the rule name. Need to do the same @@ -232,9 +230,9 @@ def translate_indirect(specification, context_module): #v = indirect.make(m, context_module) get_manager().engine().register_bjam_action(v) - result.append(get_grist(px) + "@" + m) + result.append(Property(p.feature(), "@" + m, p.condition())) else: - result.append(px) + result.append(p) return result @@ -270,24 +268,6 @@ def expand_subfeatures_in_conditions (properties): return result -def make (specification): - """ Converts implicit values into full properties. - """ - result = [] - for e in specification: - if get_grist (e): - result.append (e) - - elif feature.is_implicit_value (e): - f = feature.implied_feature (e) - result.append (f + e) - - else: - raise InvalidProperty ("'%s' is not a valid for property specification" % e) - - return result - - # FIXME: this should go def split_conditional (property): """ If 'property' is conditional property, returns diff --git a/v2/build/property_set.py b/v2/build/property_set.py index f404ae2cc..b9774de93 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -8,6 +8,7 @@ from b2.util.utility import * import property, feature, string +import b2.build.feature from b2.exceptions import * from b2.util.sequence import unique from b2.util.set import difference @@ -64,10 +65,9 @@ def create_from_user_input(raw_properties, jamfile_module, location): """Creates a property-set from the input given by the user, in the context of 'jamfile-module' at 'location'""" - specification = property.translate_paths(raw_properties, location) - specification = property.translate_indirect(specification, jamfile_module) - specification = property.make(specification) - properties = [property.create_from_string(s, True) for s in specification] + properties = property.create_from_strings(raw_properties, True) + properties = property.translate_paths(properties, location) + properties = property.translate_indirect(properties, jamfile_module) properties = property.expand_subfeatures_in_conditions(properties) return create(properties) @@ -414,15 +414,18 @@ class PropertySet: def get (self, feature): - """ Returns all properties for 'feature'. + """ Returns all values of 'feature'. """ + if not isinstance(feature, b2.build.feature.Feature): + feature = b2.build.feature.get(feature) + if not self.feature_map_: self.feature_map_ = {} for v in self.all_: if not self.feature_map_.has_key(v.feature()): self.feature_map_[v.feature()] = [] - self.feature_map_[v.feature()].append(v) + self.feature_map_[v.feature()].append(v.value()) return self.feature_map_.get(feature, []) diff --git a/v2/build/toolset.py b/v2/build/toolset.py index 9d4ff3425..eda4298e1 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -163,7 +163,7 @@ def find_satisfied_condition(conditions, ps): found = False if i.value(): - found = i in ps.get(i.feature()) + found = i.value() in ps.get(i.feature()) else: # Handle value-less properties like '' (compare with # 'x86'). @@ -310,32 +310,27 @@ def __handle_flag_value (manager, value, ps): if get_grist (value): f = feature.get(value) - properties = ps.get(f) + values = ps.get(f) - for p in properties: - - value = p.value() + for value in values: if f.dependency(): # the value of a dependency feature is a target # and must be actualized # FIXME: verify that 'find' actually works, ick! - result.append (manager.targets ().find (p.value()).actualize ()) + result.append (manager.targets ().find(value).actualize ()) elif f.path() or f.free(): - values = [] # Treat features with && in the value # specially -- each &&-separated element is considered # separate value. This is needed to handle searched # libraries, which must be in specific order. if not __re_two_ampersands.search(value): - values.append(value) + result.append(value) else: - values.extend(value.split ('&&')) - - result.extend(values) + result.extend(value.split ('&&')) else: result.append (ungristed) else: diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index ff72b4dc2..bf2bb85b5 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -290,6 +290,11 @@ def register_globals (): 'armv5t', 'armv5te', 'armv6', 'armv6j', 'iwmmxt', 'ep9312'], ['propagated', 'optional']) + + feature.feature('conditional', [], ['incidental', 'free']) + + # The value of 'no' prevents building of a target. + feature.feature('build', ['yes', 'no'], ['optional']) # Windows-specific features feature.feature ('user-interface', ['console', 'gui', 'wince', 'native', 'auto'], []) From a014f2aacb0130f160e726f1a2fabdf3794bab90 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 11:31:31 +0000 Subject: [PATCH 031/165] Handle bjam_signature in all cases where were import a callable into bjam. [SVN r64292] --- v2/build/project.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index b1ff07c49..d1c720c04 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -797,6 +797,13 @@ class ProjectRules: "error_reporting_wrapper", "add_rule_for_type"]] self.all_names_ = [x for x in self.local_names] + def _import_rule(self, bjam_module, name, callable): + if hasattr(callable, "bjam_signature"): + bjam.import_rule(bjam_module, name, self.make_wrapper(callable), callable.bjam_signature) + else: + bjam.import_rule(bjam_module, name, self.make_wrapper(callable)) + + def add_rule_for_type(self, type): rule_name = type.lower(); @@ -811,14 +818,20 @@ class ProjectRules: self.rules[name] = callable self.all_names_.append(name) + # Add new rule at global bjam scope. This might not be ideal, + # added because if a jamroot does 'import foo' where foo calls + # add_rule, we need to import new rule to jamroot scope, and + # I'm lazy to do this now. + self._import_rule("", name, callable) + def all_names(self): return self.all_names_ - def call_and_report_errors(self, callable, *args): + def call_and_report_errors(self, callable, *args, **kw): result = None try: self.manager_.errors().push_jamfile_context() - result = callable(*args) + result = callable(*args, **kw) except ExceptionWithUserContext, e: e.report() except Exception, e: @@ -835,8 +848,8 @@ class ProjectRules: """Given a free-standing function 'callable', return a new callable that will call 'callable' and report all exceptins, using 'call_and_report_errors'.""" - def wrapper(*args): - self.call_and_report_errors(callable, *args) + def wrapper(*args, **kw): + self.call_and_report_errors(callable, *args, **kw) return wrapper def init_project(self, project_module): @@ -851,12 +864,10 @@ class ProjectRules: else: n = string.replace(n, "_", "-") - bjam.import_rule(project_module, n, - self.make_wrapper(v)) + self._import_rule(project_module, n, v) for n in self.rules: - bjam.import_rule(project_module, n, - self.make_wrapper(self.rules[n])) + self._import_rule(project_module, n, self.rules[n]) def project(self, *args): @@ -990,10 +1001,7 @@ attribute is allowed only for top-level 'project' invocations""") for f in m.__dict__: v = m.__dict__[f] if callable(v): - if hasattr(v, "bjam_signature"): - bjam.import_rule(jamfile_module, name + "." + f, v, v.bjam_signature) - else: - bjam.import_rule(jamfile_module, name + "." + f, v) + self._import_rule(jamfile_module, name + "." + f, v) if names_to_import: if not local_names: @@ -1004,7 +1012,7 @@ attribute is allowed only for top-level 'project' invocations""") """The number of names to import and local names do not match.""") for n, l in zip(names_to_import, local_names): - bjam.import_rule(jamfile_module, l, m.__dict__[n]) + self._import_rule(jamfile_module, l, m.__dict__[n]) def conditional(self, condition, requirements): """Calculates conditional requirements for multiple requirements From 8fa4a55627c0c7d444255ea42afcc5183f2612a4 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 11:32:44 +0000 Subject: [PATCH 032/165] Add helper targets.metatarget_function_for_class. [SVN r64293] --- v2/build/targets.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/v2/build/targets.py b/v2/build/targets.py index e603a9486..7db023e59 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -81,7 +81,7 @@ import property, project, virtual_target, property_set, feature, generators, too from virtual_target import Subvariant from b2.exceptions import * from b2.util.sequence import unique -from b2.util import set, path +from b2.util import set, path, bjam_signature from b2.build.errors import user_error_checkpoint _re_separate_target_from_properties = re.compile (r'^([^<]*)(/(<.*))?$') @@ -1261,3 +1261,22 @@ class TypedTarget (BasicTarget): return r +def metatarget_function_for_class(class_): + + @bjam_signature((["name"], ["sources", "*"], ["requirements", "*"], + ["default_build", "*"], ["usage_requirements", "*"])) + def create_metatarget(name, sources, requirements = [], default_build = None, usage_requirements = []): + + from b2.manager import get_manager + t = get_manager().targets() + + project = get_manager().projects().current() + + return t.main_target_alternative( + class_(name, project, + t.main_target_sources(sources, name), + t.main_target_requirements(requirements, project), + t.main_target_default_build(default_build, project), + t.main_target_usage_requirements(usage_requirements, project))) + + return create_metatarget From bbbf07e16952d962a0cee059510bb8babb5ac1fe Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 12:20:22 +0000 Subject: [PATCH 033/165] Fix calling Python function taking zero parameters. [SVN r64297] --- v2/engine/src/compile.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/v2/engine/src/compile.c b/v2/engine/src/compile.c index a07e0d818..7a3f8d258 100644 --- a/v2/engine/src/compile.c +++ b/v2/engine/src/compile.c @@ -534,8 +534,15 @@ LIST * compile_rule( PARSE * parse, FRAME * 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; - for ( p = parse->left; p; p = p->left ) - lol_add( inner->args, parse_evaluate( p->right, frame ) ); + /* 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 ); From df3c844eb3763b99047503a593a4f8890e72af40 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 13:39:45 +0000 Subject: [PATCH 034/165] Make the 'generate' example work with Boost.Build/Python. [SVN r64300] --- v2/build/generators.py | 2 +- v2/build/project.py | 12 +++++++++++- v2/build/property.py | 7 +++---- v2/build/virtual_target.py | 28 ++++++++++++++++------------ v2/example/generate/gen.jam | 26 ++++++++++++++++++++++++++ v2/example/generate/gen.py | 16 ++++++++++++++++ v2/example/generate/jamroot.jam | 28 +++------------------------- v2/tools/builtin.py | 2 +- v2/tools/make.py | 13 ++++++++++--- 9 files changed, 87 insertions(+), 47 deletions(-) create mode 100644 v2/example/generate/gen.jam create mode 100644 v2/example/generate/gen.py diff --git a/v2/build/generators.py b/v2/build/generators.py index 6c02a6359..bae7e54d9 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -412,7 +412,7 @@ class Generator: pre = pre[1:] post = post[1:] - targets.append(virtual_target.FileTarget(generated_name, False, t, project, a)) + targets.append(virtual_target.FileTarget(generated_name, t, project, a)) return [ project.manager().virtual_targets().register(t) for t in targets ] diff --git a/v2/build/project.py b/v2/build/project.py index d1c720c04..77d745b77 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -794,8 +794,9 @@ class ProjectRules: self.rules = {} self.local_names = [x for x in self.__class__.__dict__ if x not in ["__init__", "init_project", "add_rule", - "error_reporting_wrapper", "add_rule_for_type"]] + "error_reporting_wrapper", "add_rule_for_type", "reverse"]] self.all_names_ = [x for x in self.local_names] + self.reverse = {} def _import_rule(self, bjam_module, name, callable): if hasattr(callable, "bjam_signature"): @@ -1002,6 +1003,7 @@ attribute is allowed only for top-level 'project' invocations""") v = m.__dict__[f] if callable(v): self._import_rule(jamfile_module, name + "." + f, v) + self.reverse.setdefault(jamfile_module, {})[name + "." + f] = v if names_to_import: if not local_names: @@ -1028,3 +1030,11 @@ attribute is allowed only for top-level 'project' invocations""") return [c + r for r in requirements] else: return [c + ":" + r for r in requirements] + + def reverse_lookup(self, jamfile_module, name_in_jamfile_modue): + """Return callable that we've previously imported to jam.""" + + if self.reverse.has_key(jamfile_module): + return self.reverse[jamfile_module].get(name_in_jamfile_modue, None) + + return None diff --git a/v2/build/property.py b/v2/build/property.py index 9a59c61a2..f0ebe2145 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -226,11 +226,10 @@ def translate_indirect(properties, context_module): # will conflict. m = context_module + "." + m - v = m - #v = indirect.make(m, context_module) - get_manager().engine().register_bjam_action(v) + v = context_module + '%' + m + get_manager().engine().register_bjam_action(m) - result.append(Property(p.feature(), "@" + m, p.condition())) + result.append(Property(p.feature(), "@" + v, p.condition())) else: result.append(p) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 61706ddf9..5ef3a49b7 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -156,7 +156,7 @@ class VirtualTargetRegistry: file_type = type.type (file) - result = FileTarget (file, False, file_type, project, + result = FileTarget (file, file_type, project, None, file_location) self.files_ [path] = result @@ -366,7 +366,7 @@ class AbstractFileTarget (VirtualTarget): type: optional type of this target. """ - def __init__ (self, name, exact, type, project, action = None): + def __init__ (self, name, type, project, action = None, exact=False): VirtualTarget.__init__ (self, name, project) self.type_ = type @@ -607,14 +607,14 @@ class FileTarget (AbstractFileTarget): - the value passed to the 'suffix' method, if any, or - the suffix which correspond to the target's type. """ - def __init__ (self, name, exact, type, project, action = None, path=None): - AbstractFileTarget.__init__ (self, name, exact, type, project, action) + def __init__ (self, name, type, project, action = None, path=None, exact=False): + AbstractFileTarget.__init__ (self, name, type, project, action, exact) self.path_ = path def clone_with_different_type(self, new_type): - return FileTarget(self.name_, 1, new_type, self.project_, - self.action_, self.path_) + return FileTarget(self.name_, new_type, self.project_, + self.action_, self.path_, exact=True) def actualize_location (self, target): engine = self.project_.manager_.engine () @@ -791,7 +791,8 @@ class Action: if i.type (): scanner = type.get_scanner (i.type (), prop_set) - result.append (i.actualize (scanner)) + r = i.actualize (scanner) + result.append (r) return result @@ -857,11 +858,14 @@ class NonScanningAction(Action): def __init__(self, sources, action_name, property_set): #FIXME: should the manager parameter of Action.__init__ #be removed? -- Steven Watanabe - Action.__init__(b2.manager.get_manager(), sources, action_name, property_set) + Action.__init__(self, b2.manager.get_manager(), sources, action_name, property_set) def actualize_source_type(self, sources, property_set): - - return [x for source in sources for x in i.actualize()] + + result = [] + for s in sources: + result.append(s.actualize()) + return result def traverse (target, include_roots = False, include_sources = False): """ Traverses the dependency graph of 'target' and return all targets that will @@ -915,8 +919,8 @@ def clone_action (action, new_project, new_action_name, new_properties): n = target.name() # Don't modify the name of the produced targets. Strip the directory f - cloned_target = FileTarget(n, 1, target.type(), new_project, - cloned_action) + cloned_target = FileTarget(n, target.type(), new_project, + cloned_action, exact=True) d = target.dependencies() if d: diff --git a/v2/example/generate/gen.jam b/v2/example/generate/gen.jam new file mode 100644 index 000000000..73232aab5 --- /dev/null +++ b/v2/example/generate/gen.jam @@ -0,0 +1,26 @@ + +import "class" : new ; +import common ; + +rule generate-example ( project name : property-set : sources * ) +{ + local result ; + for local s in $(sources) + { + #local source-name = [ $(s).name ] ; + #local source-action = [ $(s).action ] ; + #local source-properties = [ $(source-action).properties ] ; + + # Create a new action, that takes the source target and runs the + # 'common.copy' command on it. + local a = [ new non-scanning-action $(s) : common.copy : $(property-set) + ] ; + + # Create a target to represent the action result. Uses the target name + # passed here via the 'name' parameter and the same type and project as + # the source. + result += [ new file-target $(name) : [ $(s).type ] : $(project) : $(a) + ] ; + } + return $(result) ; +} \ No newline at end of file diff --git a/v2/example/generate/gen.py b/v2/example/generate/gen.py new file mode 100644 index 000000000..09ee15b43 --- /dev/null +++ b/v2/example/generate/gen.py @@ -0,0 +1,16 @@ + +from b2.build.virtual_target import NonScanningAction, FileTarget + +def generate_example(project, name, ps, sources): + + result = [] + for s in sources: + + a = NonScanningAction([s], "common.copy", ps) + + # Create a target to represent the action result. Uses the target name + # passed here via the 'name' parameter and the same type and project as + # the source. + result.append(FileTarget(name, s.type(), project, a)) + + return result diff --git a/v2/example/generate/jamroot.jam b/v2/example/generate/jamroot.jam index a244f65fc..07b8623b4 100644 --- a/v2/example/generate/jamroot.jam +++ b/v2/example/generate/jamroot.jam @@ -2,30 +2,8 @@ # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) -import "class" : new ; -import common ; +import generate ; -rule generate-example ( project name : property-set : sources * ) -{ - local result ; - for local s in $(sources) - { - #local source-name = [ $(s).name ] ; - #local source-action = [ $(s).action ] ; - #local source-properties = [ $(source-action).properties ] ; +import gen ; - # Create a new action, that takes the source target and runs the - # 'common.copy' command on it. - local a = [ new non-scanning-action $(s) : common.copy : $(property-set) - ] ; - - # Create a target to represent the action result. Uses the target name - # passed here via the 'name' parameter and the same type and project as - # the source. - result += [ new file-target $(name) : [ $(s).type ] : $(project) : $(a) - ] ; - } - return $(result) ; -} - -generate a2 : a.cpp : @generate-example ; +generate a2 : a.cpp : @gen.generate_example ; diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index bf2bb85b5..1cd30a9d2 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -316,7 +316,7 @@ register_globals () class SearchedLibTarget (virtual_target.AbstractFileTarget): def __init__ (self, name, project, shared, real_name, search, action): - virtual_target.AbstractFileTarget.__init__ (self, name, False, 'SEARCHED_LIB', project, action) + virtual_target.AbstractFileTarget.__init__ (self, name, 'SEARCHED_LIB', project, action) self.shared_ = shared self.real_name_ = real_name diff --git a/v2/tools/make.py b/v2/tools/make.py index 97fa81283..a6d476269 100644 --- a/v2/tools/make.py +++ b/v2/tools/make.py @@ -16,17 +16,24 @@ from b2.build import type from b2.manager import get_manager import b2.build.property_set +# FIXME: copy-paste from generate.py +import re +_extract_jamfile_and_rule = re.compile("@(Jamfile<.*>)%(.*)") + class MakeTarget(BasicTarget): def construct(self, name, source_targets, property_set): action_name = property_set.get("")[0] assert action_name[0] == '@' - action_name = action_name[1:] + (jamfile, rule) = _extract_jamfile_and_rule.match(action_name).groups() + # This is very bad. We need to call rule inside the proper module, + # not at global scope, where it might not be available at all. + action_name = rule action = Action(get_manager(), source_targets, action_name, property_set) - target = FileTarget(self.name(), 1, type.type(self.name()), - self.project(), action) + target = FileTarget(self.name(), type.type(self.name()), + self.project(), action, exact=True) return [ b2.build.property_set.empty(), [self.project().manager().virtual_targets().register(target)]] From 9516cf9dd3fe3493b2284097a6cff5210c87c6e5 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 14:15:46 +0000 Subject: [PATCH 035/165] Fix processing of build request. [SVN r64303] --- v2/build/build_request.py | 18 ++++++++++-------- v2/build/feature.py | 2 +- v2/build/property_set.py | 5 ++++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/v2/build/build_request.py b/v2/build/build_request.py index 8684b8320..ae85a3249 100644 --- a/v2/build/build_request.py +++ b/v2/build/build_request.py @@ -8,8 +8,8 @@ # warranty, and with no claim as to its suitability for any purpose. import feature -from b2.util import set from b2.util.utility import * +import b2.build.property_set as property_set def expand_no_defaults (property_sets): """ Expand the given build request by combining all property_sets which don't @@ -21,7 +21,7 @@ def expand_no_defaults (property_sets): # Now combine all of the expanded property_sets product = __x_product (expanded_property_sets) - return product + return [property_set.create(p) for p in product] def __x_product (property_sets): @@ -29,8 +29,7 @@ def __x_product (property_sets): that would contain conflicting values for single-valued features. """ x_product_seen = set() - x_product_used = set() - return __x_product_aux (property_sets, x_product_seen, x_product_used) + return __x_product_aux (property_sets, x_product_seen)[0] def __x_product_aux (property_sets, seen_features): """Returns non-conflicting combinations of property sets. @@ -64,14 +63,17 @@ def __x_product_aux (property_sets, seen_features): if these_features & seen_features: (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features) - return (inner_result, inner_seen + these_features) + return (inner_result, inner_seen | these_features) else: result = [] (inner_result, inner_seen) = __x_product_aux(property_sets[1:], seen_features | these_features) - for inner in inner_result: - result.append(properties + inner) + if inner_result: + for inner in inner_result: + result.append(properties + inner) + else: + result.append(properties) if inner_seen & these_features: # Some of elements in property_sets[1:] conflict with elements of property_sets[0], @@ -79,7 +81,7 @@ def __x_product_aux (property_sets, seen_features): (inner_result2, inner_seen2) = __x_product_aux(property_sets[1:], seen_features) result.extend(inner_result2) - return (result, inner_seen + these_features) + return (result, inner_seen | these_features) diff --git a/v2/build/feature.py b/v2/build/feature.py index 852c108b4..ee0c05517 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -416,7 +416,7 @@ def extend (name, values): if __implicit_features.has_key(v): raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) - __implicit_features[v] = name + __implicit_features[v] = feature if len (feature.values()) == 0 and len (values) > 0: # This is the first value specified for this feature, diff --git a/v2/build/property_set.py b/v2/build/property_set.py index b9774de93..06429bd0f 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -250,6 +250,9 @@ class PropertySet: """ return self.free_ + def non_free(self): + return self.base_ + self.incidental_ + def dependency (self): """ Returns dependency properties. """ @@ -297,7 +300,7 @@ class PropertySet: self.composites_ = create(feature.expand_composires(self.all_raw_)) return self.composites_ - def expand_subfeature(self): + def expand_subfeatures(self): if not self.subfeatures_: self.subfeatures_ = create(feature.expand_subfeatures(self.all_)) return self.subfeatures_ From 5356808752bc094c6a5c699cec69651ab922aa5b Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 23 Jul 2010 15:08:14 +0000 Subject: [PATCH 036/165] Unbreak conditional requirements work. [SVN r64305] --- v2/build/feature.py | 2 +- v2/build/property.py | 48 +++++++++++++++++++++---------------------- v2/build/targets.py | 33 +++++++++++++++++------------ v2/test/BoostBuild.py | 2 ++ 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/v2/build/feature.py b/v2/build/feature.py index ee0c05517..45a02488b 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -357,7 +357,7 @@ def __expand_subfeatures_aux (property, dont_validate = False): return result -def expand_subfeatures (properties, dont_validate = False): +def expand_subfeatures(properties, dont_validate = False): """ Make all elements of properties corresponding to implicit features explicit, and express all subfeature values as separate properties diff --git a/v2/build/property.py b/v2/build/property.py index f0ebe2145..3c7aca405 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -44,8 +44,10 @@ class Property(object): return self._condition def to_raw(self): - # FIXME: include condition! - return "<" + self._feature.name() + ">" + self._value + result = "<" + self._feature.name() + ">" + self._value + if self._condition: + result = ",".join(str(p) for p in self._condition) + ':' + result + return result def __str__(self): return self.to_raw() @@ -253,17 +255,20 @@ def expand_subfeatures_in_conditions (properties): if not p.condition(): result.append(p) + else: + expanded = [] + for c in p.condition(): - for c in p.condition(): + if c.feature().name().startswith("toolset") or c.feature().name() == "os": + # It common that condition includes a toolset which + # was never defined, or mentiones subfeatures which + # were never defined. In that case, validation will + # only produce an spirious error, so don't validate. + expanded.extend(feature.expand_subfeatures ([c], True)) + else: + expanded.extend(feature.expand_subfeatures([c])) - if c.feature().name().startswith("toolset") or c.feature().name() == "os": - # It common that condition includes a toolset which - # was never defined, or mentiones subfeatures which - # were never defined. In that case, validation will - # only produce an spirious error, so don't validate. - result.extend(feature.expand_subfeatures ([c], True)) - else: - result.extend(feature.expand_subfeatures([c])) + result.append(Property(p.feature(), p.value(), expanded)) return result @@ -311,26 +316,21 @@ def evaluate_conditionals_in_context (properties, context): in conditions are looked up in 'context' """ base = [] - conditionals = [] + conditional = [] for p in properties: - if __re_has_condition.search (p): - conditionals.append (p) + if p.condition(): + conditional.append (p) else: base.append (p) result = base - for p in conditionals: + for p in conditional: - # Separate condition and property - s = __re_separate_condition_and_property.match (p) - - # Split condition into individual properties - conditions = s.group (1).split (',') - - # Evaluate condition - if b2.util.set.contains (conditions, context): - result.append (s.group (2)) + # Evaluate condition + # FIXME: probably inefficient + if all(x in context for x in p.condition()): + result.append(Property(p.feature(), p.value())) return result diff --git a/v2/build/targets.py b/v2/build/targets.py index 7db023e59..f85fe9816 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -96,7 +96,7 @@ class TargetRegistry: # Current indent for debugging messages self.indent_ = "" - self.debug_building_ = "--debug-building" in bjam.variable("ARGV") + self.debug_building_ = "--debug-building" in bjam.variable("ARV") def main_target_alternative (self, target): """ Registers the specified target as a main target alternatives. @@ -869,17 +869,24 @@ class BasicTarget (AbstractTarget): common to dependency build request and target build properties. """ - # For optimization, we add free requirements directly, + # For optimization, we add free unconditional requirements directly, # without using complex algorithsm. - # This gives the complex algorithm better chance of caching results. - free = requirements.free () - non_free = property_set.create(requirements.base() + requirements.incidental()) - - key = (build_request, non_free) + # This gives the complex algorithm better chance of caching results. + # The exact effect of this "optimization" is no longer clear + free_unconditional = [] + other = [] + for p in requirements.all(): + if p.feature().free() and not p.condition(): + free_unconditional.append(p) + else: + other.append(p) + other = property_set.create(other) + + key = (build_request, other) if not self.request_cache.has_key(key): - self.request_cache[key] = self.__common_properties2 (build_request, non_free) + self.request_cache[key] = self.__common_properties2 (build_request, other) - return self.request_cache[key].add_raw(free) + return self.request_cache[key].add_raw(free_unconditional) # Given 'context' -- a set of already present properties, and 'requirements', # decide which extra properties should be applied to 'context'. @@ -906,7 +913,7 @@ class BasicTarget (AbstractTarget): # single # # might come from project's requirements. - + unconditional = feature.expand(requirements.non_conditional()) raw = context.all() @@ -974,14 +981,14 @@ class BasicTarget (AbstractTarget): # TODO: There is possibility that we've added bar, which is composite # and expands to bar2, but default value of is not bar2, # in which case it's not clear what to do. - # + # build_request = build_request.add_defaults() # Featured added by 'add-default' can be composite and expand # to features without default values -- so they are not added yet. # It could be clearer/faster to expand only newly added properties # but that's not critical. build_request = build_request.expand() - + return self.evaluate_requirements(requirements, build_request, "refined") @@ -1077,7 +1084,7 @@ class BasicTarget (AbstractTarget): result = GenerateResult () properties = rproperties.non_dependency () - + (p, u) = self.generate_dependencies (rproperties.dependency (), rproperties) properties += p usage_requirements = u diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 1a6169db5..0e9d26d47 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -438,6 +438,8 @@ class Tester(TestCmd.TestCmd): % os.path.join(self.original_workdir, "test-config.jam")) if ignore_toolset_requirements: kw['program'].append("--ignore-toolset-requirements") + if "--python" in sys.argv: + kw['program'].append("--python") kw['chdir'] = subdir apply(TestCmd.TestCmd.run, [self], kw) except: From eb0bc97643d7de64541f875f4a78df3128aedd3d Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 24 Jul 2010 17:22:43 +0000 Subject: [PATCH 037/165] Declare the 'install-default-prefix' feature. [SVN r64316] --- v2/tools/package.jam | 3 +++ 1 file changed, 3 insertions(+) diff --git a/v2/tools/package.jam b/v2/tools/package.jam index c96ea3d3b..a77e1f6bc 100644 --- a/v2/tools/package.jam +++ b/v2/tools/package.jam @@ -33,11 +33,14 @@ import "class" : new ; import option ; import project ; +import feature ; import property ; import stage ; import targets ; import modules ; +feature.feature install-default-prefix : : free ; + rule install ( name : requirements * : binaries * : libraries * : headers * ) { if [ MATCH --prefix=(.*) : [ modules.peek : ARGV ] ] From 39608cd666801cb2f6970f83f46ccbc3b6ea036c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sun, 25 Jul 2010 11:58:38 +0000 Subject: [PATCH 038/165] Fix computation of default install prefix. [SVN r64325] --- v2/Jamroot.jam | 4 ++-- v2/tools/package.jam | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/v2/Jamroot.jam b/v2/Jamroot.jam index 3403c2083..421e51a18 100644 --- a/v2/Jamroot.jam +++ b/v2/Jamroot.jam @@ -12,7 +12,7 @@ if [ os.on-windows ] } -package.install boost-build-engine +package.install boost-build-engine boost-build : # properties : # binaries bjam$(ext) @@ -28,7 +28,7 @@ for e in $(e1) } } -package.install-data boost-build-core +package.install-data boost-build-core : # Which subdir of $prefix/share boost-build : # What to install diff --git a/v2/tools/package.jam b/v2/tools/package.jam index a77e1f6bc..198c22315 100644 --- a/v2/tools/package.jam +++ b/v2/tools/package.jam @@ -39,10 +39,11 @@ import stage ; import targets ; import modules ; -feature.feature install-default-prefix : : free ; +feature.feature install-default-prefix : : free incidental ; -rule install ( name : requirements * : binaries * : libraries * : headers * ) +rule install ( name package-name ? : requirements * : binaries * : libraries * : headers * ) { + package-name ?= $(name) ; if [ MATCH --prefix=(.*) : [ modules.peek : ARGV ] ] { # If --prefix is explicitly specified on the command line, @@ -70,7 +71,7 @@ rule install ( name : requirements * : binaries * : libraries * : headers * ) # First, figure out all locations. Use the default if no prefix option # given. - local prefix = [ get-prefix $(requirements) ] ; + local prefix = [ get-prefix $(name) : $(requirements) ] ; # Architecture dependent files. local exec-locate = [ option.get exec-prefix : $(prefix) ] ; @@ -120,21 +121,22 @@ rule install ( name : requirements * : binaries * : libraries * : headers * ) } } -rule install-data ( target-name : directory-name : data * : requirements * ) +rule install-data ( target-name : package-name : data * : requirements * ) { + package-name ?= target-name ; if [ MATCH --prefix=(.*) : [ modules.peek : ARGV ] ] { # If --prefix is explicitly specified on the command line, # then we need wipe away any settings of datarootdir option.set datarootdir : ; - } + } - local prefix = [ get-prefix $(requirements) ] ; + local prefix = [ get-prefix $(package-name) : $(requirements) ] ; local datadir = [ option.get datarootdir : $(prefix)/share ] ; stage.install $(target-name) : $(data) - : $(requirements) $(datadir)/$(directory-name) + : $(requirements) $(datadir)/$(package-name) ; local c = [ project.current ] ; @@ -145,7 +147,7 @@ rule install-data ( target-name : directory-name : data * : requirements * ) } } -local rule get-prefix ( requirements * ) +local rule get-prefix ( package-name : requirements * ) { local prefix = [ option.get prefix : [ property.select : $(requirements) ] ] ; @@ -155,7 +157,7 @@ local rule get-prefix ( requirements * ) # Or some likely defaults if neither is given. if ! $(prefix) { - if [ modules.peek : NT ] { prefix = C:\\$(name) ; } + if [ modules.peek : NT ] { prefix = C:\\$(package-name) ; } else if [ modules.peek : UNIX ] { prefix = /usr/local ; } } return $(prefix) ; From b1641db9d073da4208ee25e444d0e9e962a67094 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 07:51:18 +0000 Subject: [PATCH 039/165] When test fails and --preserve is set, also show the command line. [SVN r64348] --- v2/test/BoostBuild.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 0e9d26d47..79daafa07 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -441,6 +441,7 @@ class Tester(TestCmd.TestCmd): if "--python" in sys.argv: kw['program'].append("--python") kw['chdir'] = subdir + self.last_program_invocation = kw['program'] apply(TestCmd.TestCmd.run, [self], kw) except: self.dump_stdio() @@ -553,6 +554,8 @@ class Tester(TestCmd.TestCmd): elif os.path.exists(path): raise "Path " + path + " already exists and is not a directory"; shutil.copytree(self.workdir, path) + print "The failed command was:" + print ' '.join(self.last_program_invocation) at = TestCmd.caller(traceback.extract_stack(), 0) annotation("stacktrace", at) From c7cf41da51d8954e3da1cdb4cac96e30fe68e66e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 08:05:16 +0000 Subject: [PATCH 040/165] Fix caching bug that caused various toolset flags to be ingored. [SVN r64349] --- v2/build/toolset.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/v2/build/toolset.py b/v2/build/toolset.py index eda4298e1..a63404cd4 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -12,6 +12,7 @@ import feature, property, generators, property_set import b2.util.set +from b2.util import cached from b2.util.utility import * from b2.util import bjam_signature @@ -139,11 +140,7 @@ def flags(rule_or_module, variable_name, condition, values = []): def set_target_variables (manager, rule_or_module, targets, ps): """ """ - settings = __stv.get(ps, None) - if not settings: - settings = __set_target_variables_aux(manager, rule_or_module, ps) - - __stv[ps] = settings + settings = __set_target_variables_aux(manager, rule_or_module, ps) if settings: for s in settings: @@ -277,6 +274,7 @@ def inherit_rules (toolset, base): ###################################################################################### # Private functions +@cached def __set_target_variables_aux (manager, rule_or_module, ps): """ Given a rule name and a property set, returns a list of tuples of variables names and values, which must be set on targets for that From 049b11e7e4f54effeb020ba1ca8698f44b979f12 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 08:07:07 +0000 Subject: [PATCH 041/165] Add decorator for caching function results. [SVN r64350] --- v2/util/__init__.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/v2/util/__init__.py b/v2/util/__init__.py index e64c0fc5e..5cee29f55 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -1,4 +1,5 @@ +# Decorator the specifies bjam-side prototype for a Python function def bjam_signature(s): def wrap(f): @@ -6,3 +7,23 @@ def bjam_signature(s): return f return wrap + +class cached(object): + + def __init__(self, function): + self.function = function + self.cache = {} + + def __call__(self, *args): + try: + return self.cache[args] + except KeyError: + v = self.function(*args) + self.cache[args] = v + return v + +def unquote(s): + if s and s[0] == '"' and s[-1] == '"': + return s[1:-1] + else: + return s From 77ee1e6c565a8a71782f6b494bc1301226bc5bdd Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 08:28:12 +0000 Subject: [PATCH 042/165] Major update of top level 'build_system.py' module. [SVN r64351] --- v2/build/build_request.py | 6 +- v2/build/targets.py | 20 +- v2/build_system.py | 1025 ++++++++++++++++++++++++++----------- v2/test/BoostBuild.py | 2 + v2/test/dll_path.py | 4 +- v2/test/explicit.py | 4 +- v2/util/option.py | 34 ++ v2/util/path.py | 105 ++-- 8 files changed, 821 insertions(+), 379 deletions(-) create mode 100644 v2/util/option.py diff --git a/v2/build/build_request.py b/v2/build/build_request.py index ae85a3249..cc9f2400a 100644 --- a/v2/build/build_request.py +++ b/v2/build/build_request.py @@ -7,7 +7,9 @@ # all copies. This software is provided "as is" without express or implied # warranty, and with no claim as to its suitability for any purpose. -import feature +import b2.build.feature +feature = b2.build.feature + from b2.util.utility import * import b2.build.property_set as property_set @@ -145,7 +147,7 @@ def convert_command_line_element(e): else: result = [e1 + "/" + e2 for e1 in result for e2 in lresult] - return result + return [property_set.create(b2.build.feature.split(r)) for r in result] ### ### rule __test__ ( ) diff --git a/v2/build/targets.py b/v2/build/targets.py index f85fe9816..d86f67a68 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -81,9 +81,11 @@ import property, project, virtual_target, property_set, feature, generators, too from virtual_target import Subvariant from b2.exceptions import * from b2.util.sequence import unique -from b2.util import set, path, bjam_signature +from b2.util import path, bjam_signature from b2.build.errors import user_error_checkpoint +import b2.util.set + _re_separate_target_from_properties = re.compile (r'^([^<]*)(/(<.*))?$') class TargetRegistry: @@ -357,7 +359,7 @@ class ProjectTarget (AbstractTarget): self.main_target_ = {} # Targets marked as explicit. - self.explicit_targets_ = [] + self.explicit_targets_ = set() # The constants defined for this project. self.constants_ = {} @@ -426,7 +428,7 @@ class ProjectTarget (AbstractTarget): # Record the name of the target, not instance, since this # rule is called before main target instaces are created. - self.explicit_.append(target_name) + self.explicit_targets_.add(target_name) def add_alternative (self, target_instance): """ Add new target alternative. @@ -575,7 +577,7 @@ class ProjectTarget (AbstractTarget): if not rules: rules = [] user_rules = [x for x in rules - if x not in self.manager().projects().project_rules()] + if x not in self.manager().projects().project_rules().all_names()] if user_rules: bjam.call("import-rules-from-parent", parent_module, this_module, user_rules) @@ -636,14 +638,14 @@ class MainTarget (AbstractTarget): best_properties = properties else: - if set.equal (properties, best_properties): + if b2.util.set.equal (properties, best_properties): return None - elif set.contains (properties, best_properties): + elif b2.util.set.contains (properties, best_properties): # Do nothing, this alternative is worse pass - elif set.contains (best_properties, properties): + elif b2.util.set.contains (best_properties, properties): best = v best_properties = properties @@ -1006,12 +1008,12 @@ class BasicTarget (AbstractTarget): # build request just to select this variant. bcondition = self.requirements_.base () ccondition = self.requirements_.conditional () - condition = set.difference (bcondition, ccondition) + condition = b2.util.set.difference (bcondition, ccondition) if debug: print " next alternative: required properties:", str(condition) - if set.contains (condition, property_set.raw ()): + if b2.util.set.contains (condition, property_set.raw ()): if debug: print " matched" diff --git a/v2/build_system.py b/v2/build_system.py index 0403d5b13..b5979f9a2 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -17,78 +17,418 @@ import b2.build.build_request from b2.build.errors import ExceptionWithUserContext import b2.tools.common +import b2.build.project as project +import b2.build.virtual_target as virtual_target +import b2.build.build_request as build_request + +import b2.util.regex + +from b2.manager import get_manager +from b2.util import cached +from b2.util import option + + import bjam import os import sys +import re -# FIXME: -# Returns the location of the build system. The primary use case -# is building Boost, where it's sometimes needed to get location -# of other components (like BoostBook files), and it's convenient -# to use location relatively to Boost.Build path. -#rule location ( ) -#{ -# local r = [ modules.binding build-system ] ; -# return $(r:P) ; -#} +################################################################################ +# +# Module global data. +# +################################################################################ -# FIXME: +# Flag indicating we should display additional debugging information related to +# locating and loading Boost Build configuration files. +debug_config = False -def get_boolean_option(name): - match = "--" + name - if match in argv: - return 1 - else: - return 0 +# Legacy option doing too many things, some of which are not even documented. +# Should be phased out. +# * Disables loading site and user configuration files. +# * Disables auto-configuration for toolsets specified explicitly on the +# command-line. +# * Causes --toolset command-line options to be ignored. +# * Prevents the default toolset from being used even if no toolset has been +# configured at all. +legacy_ignore_config = False + +# The cleaning is tricky. Say, if user says 'bjam --clean foo' where 'foo' is a +# directory, then we want to clean targets which are in 'foo' as well as those +# in any children Jamfiles under foo but not in any unrelated Jamfiles. To +# achieve this we collect a list of projects under which cleaning is allowed. +project_targets = [] + +# Virtual targets obtained when building main targets references on the command +# line. When running 'bjam --clean main_target' we want to clean only files +# belonging to that main target so we need to record which targets are produced +# for it. +results_of_main_targets = [] + +# Was an XML dump requested? +out_xml = False + +# Default toolset & version to be used in case no other toolset has been used +# explicitly by either the loaded configuration files, the loaded project build +# scripts or an explicit toolset request on the command line. If not specified, +# an arbitrary default will be used based on the current host OS. This value, +# while not strictly necessary, has been added to allow testing Boost-Build's +# default toolset usage functionality. +default_toolset = None +default_toolset_version = None + +################################################################################ +# +# Public rules. +# +################################################################################ + +# Returns the property set with the free features from the currently processed +# build request. +# +def command_line_free_features(): + return command_line_free_features + +# Sets the default toolset & version to be used in case no other toolset has +# been used explicitly by either the loaded configuration files, the loaded +# project build scripts or an explicit toolset request on the command line. For +# more detailed information see the comment related to used global variables. +# +def set_default_toolset(toolset, version=None): + default_toolset = toolset + default_toolset_version = version -def get_string_option(name): - match = "--" + name + "=" - for arg in argv: - if arg.startswith(match): - return arg[len(match):] - return None +pre_build_hook = None -def home_directories(): - if os.name == "nt": - result = set() - try: - result.add(os.environ['HOMEDRIVE'] + os.environ['HOMEPATH']) - result.add(os.environ['HOME']) - result.add(os.environ['USERPROFILE']) - except KeyError: - pass - return list(result) +def set_pre_build_hook(callable): + pre_build_hook = callable + +post_build_hook = None + +def set_post_build_hook(callable): + post_build_hook = callable + +################################################################################ +# +# Local rules. +# +################################################################################ + +# Returns actual Jam targets to be used for executing a clean request. +# +def actual_clean_targets(targets): + + # Construct a list of projects explicitly detected as targets on this build + # system run. These are the projects under which cleaning is allowed. + for t in targets: + if isinstance(t, b2.build.targets.ProjectTarget): + project_targets.append(t.project_module()) + + + # Construct a list of targets explicitly detected on this build system run + # as a result of building main targets. + targets_to_clean = set() + for t in results_of_main_targets: + # Do not include roots or sources. + targets_to_clean.update(virtual_target.traverse(t)) + + to_clean = [] + for t in get_manager().virtual_targets().all_targets(): + + # Remove only derived targets. + if t.action(): + p = t.project() + if t in targets_to_clean or should_clean_project(p.project_module()): + to_clean.append(t) + + return [t.actualize() for t in to_clean] + +_target_id_split = re.compile("(.*)//(.*)") + +# Given a target id, try to find and return the corresponding target. This is +# only invoked when there is no Jamfile in ".". This code somewhat duplicates +# code in project-target.find but we can not reuse that code without a +# project-targets instance. +# +def _find_target(target_id): + + m = _target_id_split(target_id) + if m: + pm = project.find(m.group(1), ".") else: - return [os.environ['HOME']] + pm = project.find(target_id, ".") -ignore_config = 0 -debug_config = 0 + if pm: + result = project.target(pm) -def load_config(manager, basename, path): - """Unless ignore-config is set, search configuration - basename.jam in path and loads it. The jamfile module - for that file will be loaded 'basename'.""" + if m: + result = result.find(m.group(2)) - if not ignore_config: - found = glob(path, [basename + ".jam"]) - if found: - found = found[0] + return result + +def initialize_config_module(module_name): + + get_manager().projects().initialize(module_name) + +# Helper rule used to load configuration files. Loads the first configuration +# file with the given 'filename' at 'path' into module with name 'module-name'. +# Not finding the requested file may or may not be treated as an error depending +# on the must-find parameter. Returns a normalized path to the loaded +# configuration file or nothing if no file was loaded. +# +def load_config(module_name, filename, paths, must_find=False): + + if debug_config: + print "notice: Searching '%s' for '%s' configuration file '%s." \ + % (paths, module_name, filename) + + where = None + for path in paths: + t = os.path.join(path, filename) + if os.path.exists(t): + where = t + break + + if where: + where = os.path.realpath(where) + if debug_config: - print "notice: searching '%s' for '%s.jam'" % (path, basename) - if found: - print "notice: loading %s.jam from %s" % (basename, found) + print "notice: Loading '%s' configuration file '%s' from '%s'." \ + % (module_name, filename, where) - manager.projects().load_standalone(basename, found) + # Set source location so that path-constant in config files + # with relative paths work. This is of most importance + # for project-config.jam, but may be used in other + # config files as well. + attributes = get_manager().projects().attributes(module_name) ; + attributes.set('source-location', os.path.dirname(where), True) + get_manager().projects().load_standalone(module_name, where) + + else: + msg = "Configuration file '%s' not found in '%s'." % (filename, path) + if must_find: + get_manager().errors()(msg) + + elif debug_config: + print msg + + return where + +# Loads all the configuration files used by Boost Build in the following order: +# +# -- test-config -- +# Loaded only if specified on the command-line using the --test-config +# command-line parameter. It is ok for this file not to exist even if specified. +# If this configuration file is loaded, regular site and user configuration +# files will not be. If a relative path is specified, file is searched for in +# the current folder. +# +# -- site-config -- +# Always named site-config.jam. Will only be found if located on the system +# root path (Windows), /etc (non-Windows), user's home folder or the Boost Build +# path, in that order. Not loaded in case the test-config configuration file is +# loaded or either the --ignore-site-config or the --ignore-config command-line +# option is specified. +# +# -- user-config -- +# Named user-config.jam by default or may be named explicitly using the +# --user-config command-line option or the BOOST_BUILD_USER_CONFIG environment +# variable. If named explicitly the file is looked for from the current working +# directory and if the default one is used then it is searched for in the +# user's home directory and the Boost Build path, in that order. Not loaded in +# case either the test-config configuration file is loaded, --ignore-config +# command-line option is specified or an empty file name is explicitly +# specified. If the file name has been given explicitly then the file must +# exist. +# +# Test configurations have been added primarily for use by Boost Build's +# internal unit testing system but may be used freely in other places as well. +# +def load_configuration_files(): + + # Flag indicating that site configuration should not be loaded. + ignore_site_config = "--ignore-site-config" in sys.argv + + if legacy_ignore_config and debug_config: + print "notice: Regular site and user configuration files will be ignored" + print "notice: due to the --ignore-config command-line option." + + initialize_config_module("test-config") + test_config = None + for a in sys.argv: + m = re.match("--test-config=(.*)$", a) + if m: + test_config = b2.util.unquote(m.group(1)) + break + + if test_config: + where = load_config("test-config", os.path.basename(test_config), [os.path.dirname(test_config)]) + if where: + if debug_config and not legacy_ignore_config: + print "notice: Regular site and user configuration files will" + print "notice: be ignored due to the test configuration being loaded." + + user_path = [os.path.expanduser("~")] + os.getenv("BOOST_BUILD_PATH").split(os.pathsep) + site_path = ["/etc"] + user_path + if os.name in ["nt"]: + site_path = [os.getenv("SystemRoot")] + user_path + + if ignore_site_config and not legacy_ignore_config: + print "notice: Site configuration files will be ignored due to the" + print "notice: --ignore-site-config command-line option." + + initialize_config_module("site-config") + if not test_config and not ignore_site_config and not legacy_ignore_config: + load_config('site-config', 'site-config.jam', site_path) + + initialize_config_module('user-config') + if not test_config and not legacy_ignore_config: + + user_config = None + for a in sys.argv: + m = re.match("--user-config=(.*)$", a) + if m: + user_config = m.group(1) + break + + if not user_config: + 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: + user_config = "user-config.jam" + + if explicitly_requested: + + user_config = os.path.abspath(user_config) + + if debug_config: + print "notice: Loading explicitly specified user configuration file:" + print " " + user_config + + load_config('user-config', os.path.basename(user_config), [os.path.dirname(user_config)], True) + else: + load_config('user-config', os.path.basename(user_config), user_path) + + elif debug_config: + print "notice: User configuration file loading explicitly disabled." ; + + # We look for project-config.jam from "." upward. + # I am not sure this is 100% right decision, we might as well check for + # it only alonside the Jamroot file. However: + # + # - We need to load project-root.jam before Jamroot + # - We probably would need to load project-root.jam even if there's no + # Jamroot - e.g. to implement automake-style out-of-tree builds. + if os.path.exists("project-config.jam"): + file = ["project-config.jam"] + else: + file = b2.util.path.glob_in_parents(".", ["project-config.jam"]) + + if file: + initialize_config_module('project-config') + load_config('project-config', "project-config.jam", [os.path.dirname(file[0])], True) + + +# Autoconfigure toolsets based on any instances of --toolset=xx,yy,...zz or +# toolset=xx,yy,...zz in the command line. May return additional properties to +# be processed as if they had been specified by the user. +# +def process_explicit_toolset_requests(): + + extra_properties = [] + + option_toolsets = [e for option in b2.util.regex.transform(sys.argv, "^--toolset=(.*)$") + for e in option.split(',')] + feature_toolsets = [e for option in b2.util.regex.transform(sys.argv, "^toolset=(.*)$") + for e in option.split(',')] + + for t in option_toolsets + feature_toolsets: + + # Parse toolset-version/properties. + (toolset_version, toolset, version) = re.match("(([^-/]+)-?([^/]+)?)/?.*", t).groups() + + if debug_config: + print "notice: [cmdline-cfg] Detected command-line request for '%s': toolset= %s version=%s" \ + % (toolset_version, toolset, version) + + # If the toolset is not known, configure it now. + known = False + if toolset in feature.values("toolset"): + known = True + + if known and version and not feature.is_subvalue("toolset", toolset, "version", version): + known = False + # TODO: we should do 'using $(toolset)' in case no version has been + # specified and there are no versions defined for the given toolset to + # allow the toolset to configure its default version. For this we need + # to know how to detect whether a given toolset has any versions + # defined. An alternative would be to do this whenever version is not + # specified but that would require that toolsets correctly handle the + # case when their default version is configured multiple times which + # should be checked for all existing toolsets first. + + if not known: + + if debug_config: + print "notice: [cmdline-cfg] toolset '%s' not previously configured; attempting to auto-configure now" % toolset_version + toolset.using(toolset, version) + + else: + + if debug_config: + + print "notice: [cmdline-cfg] toolset '%s' already configured" % toolset_version + + # Make sure we get an appropriate property into the build request in + # case toolset has been specified using the "--toolset=..." command-line + # option form. + if not t in sys.argv and not t in feature_toolsets: + + if debug_config: + print "notice: [cmdline-cfg] adding toolset=%s) to the build request." % t ; + extra_properties += "toolset=%s" % t + + return extra_properties + + + +# Returns 'true' if the given 'project' is equal to or is a (possibly indirect) +# child to any of the projects requested to be cleaned in this build system run. +# Returns 'false' otherwise. Expects the .project-targets list to have already +# been constructed. +# +@cached +def should_clean_project(project): + + if project in project_targets: + return True + else: + + parent = get_manager().projects().attribute(project, "parent-module") + if parent and parent != "user-config": + return should_clean_project(parent) + else: + return False + +################################################################################ +# +# main() +# ------ +# +################################################################################ def main(): - global argv - argv = bjam.variable("ARGV") + sys.argv = bjam.variable("ARGV") # FIXME: document this option. - if "--profiling" in argv: + if "--profiling" in sys.argv: import cProfile import pstats cProfile.runctx('main_real()', globals(), locals(), "stones.prof") @@ -102,217 +442,117 @@ def main(): def main_real(): - global ignore_config - global debug_config - - boost_build_path = bjam.variable("BOOST_BUILD_PATH") + global debug_config, legacy_ignore_config, out_xml + debug_config = "--debug-configuration" in sys.argv + legacy_ignore_config = "--ignore_config" in sys.argv + out_xml = any(re.match("^--out-xml=(.*)$", a) for a in sys.argv) + engine = Engine() - global_build_dir = get_string_option("build-dir") - debug_config = get_boolean_option("debug-configuration") + global_build_dir = option.get("build-dir") manager = Manager(engine, global_build_dir) + if "--version" in sys.argv: + + version.report() + return + # This module defines types and generator and what not, # and depends on manager's existence import b2.tools.builtin + b2.tools.common.init(manager) - # Check if we can load 'test-config.jam'. If we can, load it and - # ignore user configs. - - test_config = glob(boost_build_path, ["test-config.jam"]) - if test_config: - test_config = test_config[0] + load_configuration_files() - if test_config: - if debug_config: - print "notice: loading testing-config.jam from '%s'" % test_config - print "notice: user-config.jam and site-config.jam will be ignored" + extra_properties = [] + # Note that this causes --toolset options to be ignored if --ignore-config + # is specified. + if not legacy_ignore_config: + extra_properties = process_explicit_toolset_requests() - manager.projects().load_standalone("test-config", test_config) - - - ignore_config = test_config or get_boolean_option("ignore-config") - user_path = home_directories() + boost_build_path - - site_path = ["/etc"] + user_path - if bjam.variable("OS") in ["NT", "CYGWIN"]: - site_path = [os.environ("SystemRoot")] + user_path - - load_config(manager, "site-config", site_path) - - user_config_path = get_string_option("user-config") - if not user_config_path: - user_config_path = os.environ.get("BOOST_BUILD_USER_CONFIG") - - if user_config_path: - if debug_config: - print "Loading explicitly specifier user configuration file:" - print " %s" % user_config_path - - manager.projects().load_standalone("user-config", user_config_path) - - else: - load_config(manager, "user-config", user_path) - - -# FIXME: -## # -## # Autoconfigure toolsets based on any instances of --toolset=xx,yy,...zz or -## # toolset=xx,yy,...zz in the command line -## # -## local option-toolsets = [ regex.split-list [ MATCH ^--toolset=(.*) : $(argv) ] : "," ] ; -## local feature-toolsets = [ regex.split-list [ MATCH ^toolset=(.*) : $(argv) ] : "," ] ; - -## # if the user specified --toolset=..., we need to add toolset=... to -## # the build request -## local extra-build-request ; - - extra_build_request = [] - -## if ! $(ignore-config) -## { -## for local t in $(option-toolsets) $(feature-toolsets) -## { -## # Parse toolset-version/properties -## local (t-v,t,v) = [ MATCH (([^-/]+)-?([^/]+)?)/?.* : $(t) ] ; -## local toolset-version = $((t-v,t,v)[1]) ; -## local toolset = $((t-v,t,v)[2]) ; -## local version = $((t-v,t,v)[3]) ; - -## if $(debug-config) -## { -## ECHO notice: [cmdline-cfg] Detected command-line request for -## $(toolset-version): toolset= \"$(toolset)\" "version= \""$(version)\" ; -## } - -## local known ; - -## # if the toolset isn't known, configure it now. -## if $(toolset) in [ feature.values ] -## { -## known = true ; -## } - -## if $(known) && $(version) -## && ! [ feature.is-subvalue toolset : $(toolset) : version : $(version) ] -## { -## known = ; -## } - -## if ! $(known) -## { -## if $(debug-config) -## { -## ECHO notice: [cmdline-cfg] toolset $(toolset-version) -## not previously configured; configuring now ; -## } -## toolset.using $(toolset) : $(version) ; -## } -## else -## { -## if $(debug-config) -## { -## ECHO notice: [cmdline-cfg] toolset $(toolset-version) already configured ; -## } -## } - -## # make sure we get an appropriate property into the build request in -## # case the user used the "--toolset=..." form -## if ! $(t) in $(argv) -## && ! $(t) in $(feature-toolsets) -## { -## if $(debug-config) -## { -## ECHO notice: [cmdline-cfg] adding toolset=$(t) "to build request." ; -## } -## extra-build-request += toolset=$(t) ; -## } -## } -## } - - -# FIXME: -## if USER_MODULE in [ RULENAMES ] -## { -## USER_MODULE site-config user-config ; -## } - - if get_boolean_option("version"): - # FIXME: Move to a separate module. Include bjam - # verision. - print "Boost.Build M15 (Python port in development)" - sys.exit(0) - - b2.tools.common.init(manager) - - # We always load project in "." so that 'use-project' directives has - # any chance of been seen. Otherwise, we won't be able to refer to + # We always load project in "." so that 'use-project' directives have any + # chance of being seen. Otherwise, we would not be able to refer to # subprojects using target ids. - current_project = None - projects = manager.projects() + projects = get_manager().projects() if projects.find(".", "."): current_project = projects.target(projects.load(".")) - # FIXME: revive this logic, when loading of gcc works - if not feature.values("") and not ignore_config and 0: - default_toolset = "gcc" ; - if bjam.variable("OS") == "NT": - default_toolset = "msvc" - - print "warning: No toolsets are configured." ; - print "warning: Configuring default toolset '%s'" % default_toolset - print "warning: If the default is wrong, you may not be able to build C++ programs." - print "warning: Use the \"--toolset=xxxxx\" option to override our guess." + # In case there are no toolsets currently defined makes the build run using + # the default toolset. + if not legacy_ignore_config and not feature.values("toolset"): + + dt = default_toolset + dtv = None + if default_toolset: + dtv = default_toolset_version + else: + dt = "gcc" + if os.name == 'nt': + dt = "msvc" + # FIXME: + #else if [ os.name ] = MACOSX + #{ + # default-toolset = darwin ; + #} + + print "warning: No toolsets are configured." + print "warning: Configuring default toolset '%s'." % dt + print "warning: If the default is wrong, your build may not work correctly." + print "warning: Use the \"toolset=xxxxx\" option to override our guess." print "warning: For more configuration options, please consult" print "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" - projects.project_rules().using([default_toolset]) + toolset.using(dt, dtv) - (target_ids, properties) = b2.build.build_request.from_command_line( - argv[1:] + extra_build_request) - - properties = [property_set.create(feature.split(ps)) for ps in properties] + # Parse command line for targets and properties. Note that this requires + # that all project files already be loaded. + (target_ids, properties) = build_request.from_command_line(sys.argv[1:] + extra_properties) + # Expand properties specified on the command line into multiple property + # sets consisting of all legal property combinations. Each expanded property + # set will be used for a single build run. E.g. if multiple toolsets are + # specified then requested targets will be built with each of them. if properties: - expanded = b2.build.build_request.expand_no_defaults(properties) + expanded = build_request.expand_no_defaults(properties) else: expanded = [property_set.empty()] - targets = [] - - clean = get_boolean_option("clean") - clean_all = get_boolean_option("clean-all") - - - bjam_targets = [] - - # Given a target id, try to find and return corresponding target. - # This is only invoked when there's no Jamfile in "." - # This code somewhat duplicates code in project-target.find but we can't reuse - # that code without project-targets instance. - def find_target (target_id): - split = target_id.split("//") - pm = None - if len(split) > 1: - pm = projects.find(split[0], ".") - else: - pm = projects.find(target_id, ".") - - result = None - if pm: - result = projects.target(pm) - - if len(split) > 1: - result = result.find(split[1]) - + # Check that we actually found something to build. if not current_project and not target_ids: - print "error: no Jamfile in current directory found, and no target references specified." - sys.exit(1) + get_manager().errors()("no Jamfile in current directory found, and no target references specified.") + # FIXME: + # EXIT + # Flags indicating that this build system run has been started in order to + # clean existing instead of create new targets. Note that these are not the + # final flag values as they may get changed later on due to some special + # targets being specified on the command line. + clean = "--clean" in sys.argv + cleanall = "--clean-all" in sys.argv + + # List of explicitly requested files to build. Any target references read + # from the command line parameter not recognized as one of the targets + # defined in the loaded Jamfiles will be interpreted as an explicitly + # requested file to build. If any such files are explicitly requested then + # only those files and the targets they depend on will be built and they + # will be searched for among targets that would have been built had there + # been no explicitly requested files. + explicitly_requested_files = [] + + # List of Boost Build meta-targets, virtual-targets and actual Jam targets + # constructed in this build system run. + targets = [] + virtual_targets = [] + actual_targets = [] + + # Process each target specified on the command-line and convert it into + # internal Boost Build target objects. Detect special clean target. If no + # main Boost Build targets were explictly requested use the current project + # as the target. for id in target_ids: if id == "clean": clean = 1 @@ -332,7 +572,25 @@ def main_real(): if not targets: targets = [projects.target(projects.module_name("."))] + + # FIXME: put this BACK. + ## if [ option.get dump-generators : : true ] + ## { + ## generators.dump ; + ## } + + ## # We wish to put config.log in the build directory corresponding + ## # to Jamroot, so that the location does not differ depending on + ## # directory where we do build. The amount of indirection necessary + ## # here is scary. + ## local first-project = [ $(targets[0]).project ] ; + ## local first-project-root-location = [ $(first-project).get project-root ] ; + ## local first-project-root-module = [ project.load $(first-project-root-location) ] ; + ## local first-project-root = [ project.target $(first-project-root-module) ] ; + ## local first-build-build-dir = [ $(first-project-root).build-dir ] ; + ## configure.set-log-file $(first-build-build-dir)/config.log ; + virtual_targets = [] # Virtual targets obtained when building main targets references on @@ -344,6 +602,11 @@ def main_real(): # so we need to record which targets are produced. results_of_main_targets = [] + + # Now that we have a set of targets to build and a set of property sets to + # build the targets with, we can start the main build process by using each + # property set to generate virtual targets from all of our listed targets + # and any of their dependants. for p in expanded: manager.set_command_line_free_features(property_set.create(p.free())) @@ -358,78 +621,242 @@ def main_real(): except Exception: raise - # The cleaning is tricky. Say, if - # user says: - # - # bjam --clean foo - # - # where 'foo' is a directory, then we want to clean targets - # which are in 'foo' or in any children Jamfiles, but not in any - # unrelated Jamfiles. So, we collect the list of project under which - # cleaning is allowed. - # - projects_to_clean = [] - targets_to_clean = [] - if clean or clean_all: - for t in targets: - if isinstance(t, ProjectTarget): - projects_to_clean.append(t.project_module()) - - for t in results_of_main_targets: - # Don't include roots or sources. - targets_to_clean += b2.build.virtual_target.traverse(t) - - targets_to_clean = unique(targets_to_clean) - - is_child_cache_ = {} - - # Returns 'true' if 'project' is a child of 'current-project', - # possibly indirect, or is equal to 'project'. - # Returns 'false' otherwise. - def is_child (project): - - r = is_child_cache_.get(project, None) - if not r: - if project in projects_to_clean: - r = 1 - else: - parent = manager.projects().attribute(project, "parent-module") - if parent and parent != "user-config": - r = is_child(parent) - else: - r = 0 - - is_child_cache_[project] = r - - return r - - actual_targets = [] + # Convert collected virtual targets into actual raw Jam targets. for t in virtual_targets: actual_targets.append(t.actualize()) - bjam.call("NOTFILE", "all") - bjam.call("DEPENDS", "all", actual_targets) + # FIXME: restore +## # If XML data output has been requested prepare additional rules and targets +## # so we can hook into Jam to collect build data while its building and have +## # it trigger the final XML report generation after all the planned targets +## # have been built. +## if $(.out-xml) +## { +## # Get a qualified virtual target name. +## rule full-target-name ( target ) +## { +## local name = [ $(target).name ] ; +## local project = [ $(target).project ] ; +## local project-path = [ $(project).get location ] ; +## return $(project-path)//$(name) ; +## } - if bjam_targets: - bjam.call("UPDATE", ["%s" % x for x in bjam_targets]) - elif clean_all: +## # Generate an XML file containing build statistics for each constituent. +## # +## rule out-xml ( xml-file : constituents * ) +## { +## # Prepare valid XML header and footer with some basic info. +## local nl = " +## " ; +## local jam = [ version.jam ] ; +## local os = [ modules.peek : OS OSPLAT JAMUNAME ] "" ; +## local timestamp = [ modules.peek : JAMDATE ] ; +## local cwd = [ PWD ] ; +## local command = $(.sys.argv) ; +## local bb-version = [ version.boost-build ] ; +## .header on $(xml-file) = +## "" +## "$(nl)" +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## ; +## .footer on $(xml-file) = +## "$(nl)" ; + +## # Generate the target dependency graph. +## .contents on $(xml-file) += +## "$(nl) " ; +## for local t in [ virtual-target.all-targets ] +## { +## local action = [ $(t).action ] ; +## if $(action) +## # If a target has no action, it has no dependencies. +## { +## local name = [ full-target-name $(t) ] ; +## local sources = [ $(action).sources ] ; +## local dependencies ; +## for local s in $(sources) +## { +## dependencies += [ full-target-name $(s) ] ; +## } + +## local path = [ $(t).path ] ; +## local jam-target = [ $(t).actual-name ] ; + +## .contents on $(xml-file) += +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " +## ; +## } +## } +## .contents on $(xml-file) += +## "$(nl) " ; + +## # Build $(xml-file) after $(constituents). Do so even if a +## # constituent action fails and regenerate the xml on every bjam run. +## INCLUDES $(xml-file) : $(constituents) ; +## ALWAYS $(xml-file) ; +## __ACTION_RULE__ on $(xml-file) = build-system.out-xml.generate-action ; +## out-xml.generate $(xml-file) ; +## } + +## # The actual build actions are here; if we did this work in the actions +## # clause we would have to form a valid command line containing the +## # result of @(...) below (the name of the XML file). +## # +## rule out-xml.generate-action ( args * : xml-file +## : command status start end user system : output ? ) +## { +## local contents = +## [ on $(xml-file) return $(.header) $(.contents) $(.footer) ] ; +## local f = @($(xml-file):E=$(contents)) ; +## } + +## # Nothing to do here; the *real* actions happen in +## # out-xml.generate-action. +## actions quietly out-xml.generate { } + +## # Define the out-xml file target, which depends on all the targets so +## # that it runs the collection after the targets have run. +## out-xml $(.out-xml) : $(actual-targets) ; + +## # Set up a global __ACTION_RULE__ that records all the available +## # statistics about each actual target in a variable "on" the --out-xml +## # target. +## # +## rule out-xml.collect ( xml-file : target : command status start end user +## system : output ? ) +## { +## local nl = " +## " ; +## # Open the action with some basic info. +## .contents on $(xml-file) += +## "$(nl) " ; + +## # If we have an action object we can print out more detailed info. +## local action = [ on $(target) return $(.action) ] ; +## if $(action) +## { +## local action-name = [ $(action).action-name ] ; +## local action-sources = [ $(action).sources ] ; +## local action-props = [ $(action).properties ] ; + +## # The qualified name of the action which we created the target. +## .contents on $(xml-file) += +## "$(nl) " ; + +## # The sources that made up the target. +## .contents on $(xml-file) += +## "$(nl) " ; +## for local source in $(action-sources) +## { +## local source-actual = [ $(source).actual-name ] ; +## .contents on $(xml-file) += +## "$(nl) " ; +## } +## .contents on $(xml-file) += +## "$(nl) " ; + +## # The properties that define the conditions under which the +## # target was built. +## .contents on $(xml-file) += +## "$(nl) " ; +## for local prop in [ $(action-props).raw ] +## { +## local prop-name = [ MATCH ^<(.*)>$ : $(prop:G) ] ; +## .contents on $(xml-file) += +## "$(nl) " ; +## } +## .contents on $(xml-file) += +## "$(nl) " ; +## } + +## local locate = [ on $(target) return $(LOCATE) ] ; +## locate ?= "" ; +## .contents on $(xml-file) += +## "$(nl) " +## "$(nl) " +## "$(nl) " +## "$(nl) " ; +## .contents on $(xml-file) += +## "$(nl) " ; +## } + +## # When no __ACTION_RULE__ is set "on" a target, the search falls back to +## # the global module. +## module +## { +## __ACTION_RULE__ = build-system.out-xml.collect +## [ modules.peek build-system : .out-xml ] ; +## } + +## IMPORT +## build-system : +## out-xml.collect +## out-xml.generate-action +## : : +## build-system.out-xml.collect +## build-system.out-xml.generate-action +## ; +## } + + j = option.get("jobs") + if j: + bjam.call("set-variable", PARALLELISM, j) + + k = option.get("keep-going", "true", "true") + if k in ["on", "yes", "true"]: + bjam.call("set-variable", "KEEP_GOING", "1") + elif k in ["off", "no", "false"]: + bjam.call("set-variable", "KEEP_GOING", "0") + else: + print "error: Invalid value for the --keep-going option" + sys.exit() + + # The 'all' pseudo target is not strictly needed expect in the case when we + # use it below but people often assume they always have this target + # available and do not declare it themselves before use which may cause + # build failures with an error message about not being able to build the + # 'all' target. + bjam.call("NOTFILE", "all") + + # And now that all the actual raw Jam targets and all the dependencies + # between them have been prepared all that is left is to tell Jam to update + # those targets. + if explicitly_requested_files: + # Note that this case can not be joined with the regular one when only + # exact Boost Build targets are requested as here we do not build those + # requested targets but only use them to construct the dependency tree + # needed to build the explicitly requested files. + # FIXME: add $(.out-xml) + bjam.call("UPDATE", ["%s" % x for x in explicitly_requested_files]) + elif cleanall: bjam.call("UPDATE", "clean-all") elif clean: - to_clean = [] - for t in manager.virtual_targets().all_targets(): - p = t.project() - - # Remove only derived targets. - if t.action() and \ - (t in targets_to_clean or is_child(p.project_module())): - to_clean.append(t) - - to_clean_actual = [t.actualize() for t in to_clean] - manager.engine().set_update_action('common.Clean', 'clean', - to_clean_actual, None) - + manager.engine().set_update_action("common.Clean", "clean", + actual_clean_targets(targets), None) bjam.call("UPDATE", "clean") - else: - bjam.call("UPDATE", "all") + # FIXME: + #configure.print-configure-checks-summary ; + + if pre_build_hook: + pre_build_hook() + + bjam.call("DEPENDS", "all", actual_targets) + ok = bjam.call("UPDATE_NOW", "all") # FIXME: add out-xml + if post_build_hook: + post_build_hook(ok) + # Prevent automatic update of the 'all' target, now that + # we have explicitly updated what we wanted. + bjam.call("UPDATE") diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 79daafa07..6be72abed 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -668,6 +668,8 @@ class Tester(TestCmd.TestCmd): self.ignore("bin/config.log") + self.ignore("*.pyc") + if not self.unexpected_difference.empty(): annotation('failure', 'Unexpected changes found') output = StringIO.StringIO() diff --git a/v2/test/dll_path.py b/v2/test/dll_path.py index 4efc2019c..a02b2b04e 100644 --- a/v2/test/dll_path.py +++ b/v2/test/dll_path.py @@ -29,10 +29,10 @@ int main() {} """) t.write("jamroot.jam", """ -using dll-paths ; +using dll_paths ; """) -t.write("dll-paths.jam", """ +t.write("dll_paths.jam", """ import type ; import generators ; import feature ; diff --git a/v2/test/explicit.py b/v2/test/explicit.py index 2665becf8..43137402b 100644 --- a/v2/test/explicit.py +++ b/v2/test/explicit.py @@ -8,9 +8,7 @@ import BoostBuild t = BoostBuild.Tester() -t.write("jamroot.jam", "") - -t.write("jamfile.jam", """ +t.write("jamroot.jam", """ exe hello : hello.cpp ; exe hello2 : hello.cpp ; explicit hello2 ; diff --git a/v2/util/option.py b/v2/util/option.py new file mode 100644 index 000000000..1f253f1c4 --- /dev/null +++ b/v2/util/option.py @@ -0,0 +1,34 @@ +# Copyright (c) 2005-2010 Vladimir Prus. +# +# Use, modification and distribution is subject to the Boost Software +# License Version 1.0. (See accompanying file LICENSE_1_0.txt or +# http://www.boost.org/LICENSE_1_0.txt) + +import sys +import b2.util.regex + +options = {} + +# Set a value for a named option, to be used when not overridden on the command +# line. +def set(name, value=None): + + global options + + options[name] = value + +def get(name, default_value=None, implied_value=None): + + global options + + matches = b2.util.regex.transform(sys.argv, "--$(name)=(.*)") + if matches: + return matches[-1] + else: + m = b2.util.regex.transform(sys.argv, "--$(name)") + if m and implied_value: + return implied_value + elif options.has_key(name): + return options[name] + else: + return default_value diff --git a/v2/util/path.py b/v2/util/path.py index f5cbc63f3..dc02d2497 100644 --- a/v2/util/path.py +++ b/v2/util/path.py @@ -303,70 +303,47 @@ def glob (dirs, patterns): result.extend (glob.glob (p)) return result -# # -# # Returns true is the specified file exists. -# # -# rule exists ( file ) -# { -# return [ path.glob $(file:D) : $(file:D=) ] ; -# } -# NATIVE_RULE path : exists ; -# -# -# -# # -# # Find out the absolute name of path and returns the list of all the parents, -# # starting with the immediate one. Parents are returned as relative names. -# # If 'upper_limit' is specified, directories above it will be pruned. -# # -# rule all-parents ( path : upper_limit ? : cwd ? ) -# { -# cwd ?= [ pwd ] ; -# local path_ele = [ regex.split [ root $(path) $(cwd) ] "/" ] ; -# -# if ! $(upper_limit) { -# upper_limit = / ; -# } -# local upper_ele = [ regex.split [ root $(upper_limit) $(cwd) ] "/" ] ; -# -# # Leave only elements in 'path_ele' below 'upper_ele' -# while $(path_ele) && $(upper_ele[1]) = $(path_ele[1]) { -# upper_ele = $(upper_ele[2-]) ; -# path_ele = $(path_ele[2-]) ; -# } -# -# # All upper elements removed ? -# if ! $(upper_ele) { -# # Create the relative paths to parents, number of elements in 'path_ele' -# local result ; -# for local i in $(path_ele) { -# path = [ parent $(path) ] ; -# result += $(path) ; -# } -# return $(result) ; -# } -# else { -# error "$(upper_limit) is not prefix of $(path)" ; -# } -# } -# -# -# # -# # Search for 'pattern' in parent directories of 'dir', up till and including -# # 'upper_limit', if it is specified, or till the filesystem root otherwise. -# # -# rule glob-in-parents ( dir : patterns + : upper-limit ? ) -# { -# local result ; -# local parent-dirs = [ all-parents $(dir) : $(upper-limit) ] ; -# -# while $(parent-dirs) && ! $(result) -# { -# result = [ glob $(parent-dirs[1]) : $(patterns) ] ; -# parent-dirs = $(parent-dirs[2-]) ; -# } -# return $(result) ; -# } +# +# Find out the absolute name of path and returns the list of all the parents, +# starting with the immediate one. Parents are returned as relative names. +# If 'upper_limit' is specified, directories above it will be pruned. +# +def all_parents(path, upper_limit=None, cwd=None): + + if not cwd: + cwd = os.getcwd() + + path_abs = os.path.join(cwd, path) + + if upper_limit: + upper_limit = os.path.join(cwd, upper_limit) + + result = [] + while path_abs and path_abs != upper_limit: + (head, tail) = os.path.split(path) + path = os.path.join(path, "..") + result.append(path) + path_abs = head + + if upper_limit and path_abs != upper_limit: + raise BaseException("'%s' is not a prefix of '%s'" % (upper_limit, path)) + + return result + +# Search for 'pattern' in parent directories of 'dir', up till and including +# 'upper_limit', if it is specified, or till the filesystem root otherwise. +# +def glob_in_parents(dir, patterns, upper_limit=None): + + result = [] + parent_dirs = all_parents(dir, upper_limit) + + for p in parent_dirs: + result = glob(p, patterns) + if result: break + + return result + # # # # # Assuming 'child' is a subdirectory of 'parent', return the relative From 3744ff86cc4e8489d64ae6e0559d27a60b99bf63 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 09:20:54 +0000 Subject: [PATCH 043/165] Make test framework not crash when reading nonexistent file [SVN r64353] --- v2/test/BoostBuild.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 6be72abed..8c5024f15 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -525,7 +525,10 @@ class Tester(TestCmd.TestCmd): return '' def read_and_strip(self, name): - lines = open(self.glob_file(name), "rb").readlines() + if not self.glob_file(name): + return '' + f = open(self.glob_file(name), "rb") + lines = f.readlines() result = string.join(map(string.rstrip, lines), "\n") if lines and lines[-1][-1] == '\n': return result + '\n' From 311cf18c90dd4c454c68716e4c9117d63fcad9f2 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 09:21:53 +0000 Subject: [PATCH 044/165] Fix grabbing of BOOST_BUILD_PATH from environment [SVN r64354] --- v2/build_system.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/v2/build_system.py b/v2/build_system.py index b5979f9a2..7146579c2 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -1,4 +1,6 @@ -# Status: being ported by Vladimir Prus. +# Status: mostly ported. Missing is --out-xml support, 'configure' integration +# and some FIXME. +# Base revision: 64351 # Copyright 2003, 2005 Dave Abrahams # Copyright 2006 Rene Rivera @@ -270,7 +272,7 @@ def load_configuration_files(): print "notice: Regular site and user configuration files will" print "notice: be ignored due to the test configuration being loaded." - user_path = [os.path.expanduser("~")] + os.getenv("BOOST_BUILD_PATH").split(os.pathsep) + user_path = [os.path.expanduser("~")] + bjam.variable("BOOST_BUILD_PATH") site_path = ["/etc"] + user_path if os.name in ["nt"]: site_path = [os.getenv("SystemRoot")] + user_path From 3c3d67ecb01ccdc6843e7d00cf7995220a75c4d8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 09:55:45 +0000 Subject: [PATCH 045/165] Fix project loading. - If we have Jamroot and Jamfile, load both - Actually inherit build-dir from parent. [SVN r64355] --- v2/build/project.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 77d745b77..ff50f224d 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -280,7 +280,8 @@ Attempted to find it with pattern '%s'. Please consult the documentation at 'http://boost.org/boost-build2'.""" % (dir, string.join(self.JAMFILE))) - return jamfile_glob[0] + if jamfile_glob: + return jamfile_glob[0] def load_jamfile(self, dir): """Load a Jamfile at the given directory. Returns nothing. @@ -288,10 +289,12 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" Effect of calling this rule twice with the same 'dir' is underfined.""" # See if the Jamfile is where it should be. + is_jamroot = False jamfile_to_load = b2.util.path.glob([dir], self.JAMROOT) if not jamfile_to_load: jamfile_to_load = self.find_jamfile(dir) else: + is_jamroot = True jamfile_to_load = jamfile_to_load[0] # The module of the jamfile. @@ -319,7 +322,12 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" bjam.call("load", jamfile_module, jamfile_to_load) basename = os.path.basename(jamfile_to_load) - + + if is_jamroot: + jamfile = self.find_jamfile(dir, no_errors=True) + if jamfile: + bjam.call("load", jamfile_module, jamfile) + # Now do some checks if self.current_project != saved_project: self.manager.errors()( @@ -482,8 +490,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) parent_dir = os.path.join(os.getcwd(), parent_location) build_dir = os.path.join(parent_build_dir, - b2.util.path.relpath(parent_dir, - our_dir)) + os.path.relpath(our_dir, parent_dir)) + attributes.set("build-dir", build_dir, exact=True) def register_id(self, id, module): """Associate the given id with the given project module.""" @@ -747,7 +755,7 @@ class ProjectAttributes: self.__dict__["source-location"] = source_location elif attribute == "build-dir": - self.__dict__["build-dir"] = os.path.join(self.location, specification) + self.__dict__["build-dir"] = os.path.join(self.location, specification[0]) elif not attribute in ["id", "default-build", "location", "source-location", "parent", From fa7f2cb8accbdf1ed7fe13439b89ef7e4518f692 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 11:40:00 +0000 Subject: [PATCH 046/165] Make build-dir project attribute and command-line option work. [SVN r64357] --- v2/build/project.py | 22 +++++++++++----------- v2/build/targets.py | 3 +-- v2/build_system.py | 1 - v2/test/build_dir.py | 2 +- v2/util/option.py | 5 +++-- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index ff50f224d..a772edc41 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -56,7 +56,7 @@ class ProjectRegistry: def __init__(self, manager, global_build_dir): self.manager = manager - self.global_build_dir = None + self.global_build_dir = global_build_dir self.project_rules_ = ProjectRules(self) # The target corresponding to the project being loaded now @@ -339,7 +339,7 @@ expected value %s actual value %s""" % (jamfile_module, saved_project, self.current_project)) if self.global_build_dir: - id = self.attribute(jamfile_module, "id") + id = self.attributeDefault(jamfile_module, "id", None) project_root = self.attribute(jamfile_module, "project-root") location = self.attribute(jamfile_module, "location") @@ -393,8 +393,6 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # source paths are correct. if not location: location = "" - else: - location = b2.util.path.relpath(os.getcwd(), location) attributes = ProjectAttributes(self.manager, location, module_name) self.module2attributes[module_name] = attributes @@ -523,8 +521,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) try: return self.module2attributes[project].get(attribute) except: - print "Sucks", project, attribute - raise "Sucks" + raise BaseException("No attribute '%s' for project" % (attribute, project)) def attributeDefault(self, project, attribute, default): """Returns the value of the specified attribute in the @@ -708,7 +705,7 @@ class ProjectAttributes: self.attributes = {} self.usage_requirements = None - def set(self, attribute, specification, exact): + def set(self, attribute, specification, exact=False): """Set the named attribute from the specification given by the user. The value actually set may be different.""" @@ -893,6 +890,8 @@ class ProjectRules: id = '/' + id self.registry.register_id (id, jamfile_module) + attributes.set('id', id) + explicit_build_dir = None for a in args: if a: @@ -912,16 +911,17 @@ class ProjectRules: # This is Jamroot. if id: if explicit_build_dir and os.path.isabs(explicit_build_dir): - self.register.manager.errors()( + self.registry.manager.errors()( """Absolute directory specified via 'build-dir' project attribute Don't know how to combine that with the --build-dir option.""") rid = id if rid[0] == '/': rid = rid[1:] - - p = os.path.join(self.registry.global_build_dir, - rid, explicit_build_dir) + + p = os.path.join(self.registry.global_build_dir, rid) + if explicit_build_dir: + p = os.path.join(p, explicit_build_dir) attributes.set("build-dir", p, exact=1) elif explicit_build_dir: self.registry.manager.errors()( diff --git a/v2/build/targets.py b/v2/build/targets.py index d86f67a68..30bbf6fdd 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -380,8 +380,7 @@ class ProjectTarget (AbstractTarget): if not self.build_dir_: self.build_dir_ = self.get ('build-dir') if not self.build_dir_: - self.build_dir_ = os.path.join (os.path.dirname( - self.project_.get ('location')), 'bin') + self.build_dir_ = os.path.join(self.project_.get ('location'), 'bin') return self.build_dir_ diff --git a/v2/build_system.py b/v2/build_system.py index 7146579c2..57f41cff8 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -453,7 +453,6 @@ def main_real(): engine = Engine() global_build_dir = option.get("build-dir") - manager = Manager(engine, global_build_dir) if "--version" in sys.argv: diff --git a/v2/test/build_dir.py b/v2/test/build_dir.py index c5bcbc5b9..ad5327979 100644 --- a/v2/test/build_dir.py +++ b/v2/test/build_dir.py @@ -99,7 +99,7 @@ exe a : a.cpp ; build-project sub ; """ % string.replace(os.getcwd(), '\\', '\\\\')) -t.run_build_system("--build-dir=build", status=1) +t.run_build_system("--build-dir=build") t.fail_test(string.find(t.stdout(), "Absolute directory specified via 'build-dir' project attribute") == -1) diff --git a/v2/util/option.py b/v2/util/option.py index 1f253f1c4..bf0eb2346 100644 --- a/v2/util/option.py +++ b/v2/util/option.py @@ -5,6 +5,7 @@ # http://www.boost.org/LICENSE_1_0.txt) import sys +import re import b2.util.regex options = {} @@ -21,11 +22,11 @@ def get(name, default_value=None, implied_value=None): global options - matches = b2.util.regex.transform(sys.argv, "--$(name)=(.*)") + matches = b2.util.regex.transform(sys.argv, "--" + re.escape(name) + "=(.*)") if matches: return matches[-1] else: - m = b2.util.regex.transform(sys.argv, "--$(name)") + m = b2.util.regex.transform(sys.argv, "--" + re.escape(name)) if m and implied_value: return implied_value elif options.has_key(name): From 81a2f8ff69a40d8a5d12b3e8d796a593ed7f4967 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 11:49:10 +0000 Subject: [PATCH 047/165] Respect 'no'. [SVN r64358] --- v2/build/targets.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/v2/build/targets.py b/v2/build/targets.py index 30bbf6fdd..fbf547cbc 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -1068,7 +1068,7 @@ class BasicTarget (AbstractTarget): self.manager().targets().log( "Target requirements: %s'" % str (self.requirements().raw ())) - if not self.generated_.has_key (str (ps)): + if not self.generated_.has_key(ps): # Apply free features form the command line. If user # said @@ -1079,8 +1079,8 @@ class BasicTarget (AbstractTarget): self.manager().targets().log( "Common properties are '%s'" % str (rproperties.raw ())) - - if rproperties.get("") != "no": + + if rproperties.get("") != ["no"]: result = GenerateResult () @@ -1131,9 +1131,9 @@ class BasicTarget (AbstractTarget): "Usage requirements from '%s' are '%s'" % (self.name, str(rproperties.raw()))) - self.generated_ [str (ps)] = GenerateResult (ur, result) + self.generated_[ps] = GenerateResult (ur, result) else: - self.generated_ [str (ps)] = GenerateResult (property_set.empty(), []) + self.generated_[ps] = GenerateResult (property_set.empty(), []) else: self.manager().targets().log( "Skipping build: no in common properties") @@ -1142,13 +1142,13 @@ class BasicTarget (AbstractTarget): # properties, or there's no in properties. # In the latter case we don't want any diagnostic. # In the former case, we need diagnostics. TODOo - self.generated_ [str (ps)] = GenerateResult (rproperties, []) + self.generated_[ps] = GenerateResult (rproperties, []) else: self.manager().targets().log ("Already built") self.manager().targets().decrease_indent() - return self.generated_ [str (ps)] + return self.generated_[ps] def generate_from_reference (self, target_reference, project, property_set): """ Attempts to generate the target given by target reference, which From dfaccf477eaa79e6aa45a0b1e10b74f7bba74534 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 12:05:10 +0000 Subject: [PATCH 048/165] When refining properties, actually remove properties that are overridden. [SVN r64359] --- v2/build/property.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/build/property.py b/v2/build/property.py index 3c7aca405..ddbd50c46 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -160,7 +160,7 @@ def refine (properties, requirements): # Record them so that we can handle 'properties'. for r in requirements: # Don't consider conditional requirements. - if r.condition(): + if not r.condition(): required[r.feature()] = r for p in properties: From 58f1d1f5fe34dac0e92592136b060c6929c5a0ce Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 12:06:11 +0000 Subject: [PATCH 049/165] Respect --debug-building. [SVN r64360] --- v2/build/targets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/build/targets.py b/v2/build/targets.py index fbf547cbc..94d7f33bb 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -98,7 +98,7 @@ class TargetRegistry: # Current indent for debugging messages self.indent_ = "" - self.debug_building_ = "--debug-building" in bjam.variable("ARV") + self.debug_building_ = "--debug-building" in bjam.variable("ARGV") def main_target_alternative (self, target): """ Registers the specified target as a main target alternatives. @@ -919,7 +919,7 @@ class BasicTarget (AbstractTarget): raw = context.all() raw = property.refine(raw, unconditional) - + # We've collected properties that surely must be present in common # properties. We now try to figure out what other properties # should be added in order to satisfy rules (4)-(6) from the docs. From 4118c725d1e1467c90f8e59158f6fc128f94dec0 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 12:13:12 +0000 Subject: [PATCH 050/165] Add bjam_signature for feature.compose and feature.subfeature. [SVN r64361] --- v2/build/feature.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/v2/build/feature.py b/v2/build/feature.py index 45a02488b..208969802 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -487,6 +487,8 @@ def extend_subfeature (feature_name, value_string, subfeature_name, subvalues): for subvalue in subvalues: __subfeature_from_value [feature][value_string][subvalue] = subfeature +@bjam_signature((["feature_name", "value_string", "?"], ["subfeature"], + ["subvalues", "*"], ["attributes", "*"])) def subfeature (feature_name, value_string, subfeature, subvalues, attributes = []): """ Declares a subfeature. feature_name: Root feature that is not a subfeature. @@ -517,6 +519,7 @@ def subfeature (feature_name, value_string, subfeature, subvalues, attributes = extend_subfeature (feature_name, value_string, subfeature, subvalues) +@bjam_signature((["composite_property_s"], ["component_properties_s", "*"])) def compose (composite_property_s, component_properties_s): """ Sets the components of the given composite property. From 375ac8bd0f6870f981d552d10abca5a6592c2ef0 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 12:41:34 +0000 Subject: [PATCH 051/165] Robustify feature.is_implicit_value. [SVN r64362] --- v2/build/feature.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/v2/build/feature.py b/v2/build/feature.py index 208969802..3d071c8bc 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -246,6 +246,10 @@ def is_implicit_value (value_string): """ Returns true iff 'value_string' is a value_string of an implicit feature. """ + + if __implicit_features.has_key(value_string): + return __implicit_features[value_string] + v = value_string.split('-') if not __implicit_features.has_key(v[0]): From ea5ff9e17381c2b5db1fa9c9179addce48b87b08 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 12:42:27 +0000 Subject: [PATCH 052/165] Export the 'variant' rule to Jamfiles [SVN r64363] --- v2/tools/builtin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index 1cd30a9d2..44d203f3f 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -11,10 +11,11 @@ import sys from b2.build import feature, property, virtual_target, generators, type, property_set, scanner from b2.util.utility import * -from b2.util import path, regex +from b2.util import path, regex, bjam_signature import b2.tools.types from b2.manager import get_manager + # Records explicit properties for a variant. # The key is the variant name. __variant_explicit_properties = {} @@ -26,6 +27,7 @@ def reset (): __variant_explicit_properties = {} +@bjam_signature((["name"], ["parents_or_properties", "*"], ["explicit_properties", "*"])) def variant (name, parents_or_properties, explicit_properties = []): """ Declares a new variant. First determines explicit properties for this variant, by @@ -721,3 +723,5 @@ class ArchiveGenerator (generators.Generator): ### ### ### + +get_manager().projects().add_rule("variant", variant) From dd2dac3880d0ee5dd95a716f2a02b6820843476f Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 26 Jul 2010 13:04:29 +0000 Subject: [PATCH 053/165] Fix removing of parent project requirements [SVN r64364] --- v2/build/property_set.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/build/property_set.py b/v2/build/property_set.py index 06429bd0f..4f7a0afcc 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -105,8 +105,8 @@ def refine_from_user_input(parent_requirements, specification, jamfile_module, ps = create_from_user_input(remove_requirements, jamfile_module, location) - parent_requirements = create(difference(parent_requirements.raw(), - ps.raw())) + parent_requirements = create(difference(parent_requirements.all(), + ps.all())) specification = add_requirements requirements = create_from_user_input(specification, From 57ea500e02a10bca19d291b2b7d081fd855a40a8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 27 Jul 2010 10:56:38 +0000 Subject: [PATCH 054/165] Use Property, not string, in more places [SVN r64382] --- v2/build/feature.py | 25 +++++++++++++------------ v2/build/generators.py | 13 +++++++------ v2/build/property.py | 3 +++ v2/build/property_set.py | 15 +++++++++------ v2/build/targets.py | 38 ++++++++++++++++---------------------- v2/build/virtual_target.py | 5 ++++- v2/build_system.py | 13 ++----------- v2/tools/gcc.py | 9 ++++----- 8 files changed, 58 insertions(+), 63 deletions(-) diff --git a/v2/build/feature.py b/v2/build/feature.py index 3d071c8bc..3f09d9da5 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -835,27 +835,28 @@ def compress_subproperties (properties): purposes and it needs help """ result = [] - matched_subs = [] + matched_subs = set() + all_subs = set() for p in properties: - pg = get_grist (p) - if not pg: - raise BaseException ("Gristed variable exppected. Got '%s'." % p) + f = p.feature() - if not __all_features [pg].subfeature(): + if not f.subfeature(): subs = __select_subproperties (p, properties) + if subs: - matched_subs.extend (subs) + matched_subs.update(subs) - subvalues = '-'.join (get_value (subs)) - if subvalues: subvalues = '-' + subvalues - - result.append (p + subvalues) + subvalues = '-'.join (sub.value() for sub in subs) + result.append(Property(p.feature(), p.value + '-' + subvalues, + p.condition())) + else: + result.append(p) else: - all_subs.append (p) + all_subs.add(p) # TODO: this variables are used just for debugging. What's the overhead? - assert (b2.util.set.equal (all_subs, matched_subs)) + assert all_subs == matched_subs return result diff --git a/v2/build/generators.py b/v2/build/generators.py index bae7e54d9..ab461f984 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -238,7 +238,7 @@ class Generator: """ return self.requirements_ - def match_rank (self, property_set_to_match): + def match_rank (self, ps): """ Returns true if the generator can be run with the specified properties. """ @@ -250,17 +250,18 @@ class Generator: property_requirements = [] feature_requirements = [] + # This uses strings because genenator requirements allow + # the '' syntax without value and regular validation + # is not happy about that. for r in all_requirements: if get_value (r): property_requirements.append (r) else: feature_requirements.append (r) - - properties_to_match = property_set_to_match.raw () - - return set.contains (property_requirements, properties_to_match) \ - and set.contains (feature_requirements, get_grist (properties_to_match)) + + return all(ps.get(get_grist(s)) == [get_value(s)] for s in property_requirements) \ + and all(ps.get(get_grist(s)) for s in feature_requirements) def run (self, project, name, prop_set, sources): """ Tries to invoke this generator on the given sources. Returns a diff --git a/v2/build/property.py b/v2/build/property.py index ddbd50c46..5eeea1a8a 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -64,6 +64,9 @@ class Property(object): def create_from_string(s, allow_condition = False): condition = [] + import types + if not isinstance(s, types.StringType): + print type(s) if __re_has_condition.search(s): if not allow_condition: diff --git a/v2/build/property_set.py b/v2/build/property_set.py index 4f7a0afcc..dc3dcc32d 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -142,6 +142,7 @@ class PropertySet: self.all_ = properties self.all_raw_ = raw_properties + self.all_set_ = set(properties) self.incidental_ = [] self.free_ = [] @@ -238,7 +239,7 @@ class PropertySet: return self.all_raw_ def __str__(self): - return string.join(self.all_raw_) + return ' '.join(str(p) for p in self.all_) def base (self): """ Returns properties that are neither incidental nor free. @@ -295,11 +296,6 @@ class PropertySet: self.expanded_ = create(expanded) return self.expanded_ - def expand_componsite(self): - if not self.componsites_: - self.composites_ = create(feature.expand_composires(self.all_raw_)) - return self.composites_ - def expand_subfeatures(self): if not self.subfeatures_: self.subfeatures_ = create(feature.expand_subfeatures(self.all_)) @@ -431,4 +427,11 @@ class PropertySet: self.feature_map_[v.feature()].append(v.value()) return self.feature_map_.get(feature, []) + + def __contains__(self, item): + for p in self.all_set_: + if p.feature().name() == "toolset": + print "EXISTING", hash(p), hash(p._feature), hash(p._value), "--", hash(item._feature), has(item._value) + print self.all_set_ + return item in self.all_set_ diff --git a/v2/build/targets.py b/v2/build/targets.py index 94d7f33bb..39b127a5c 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -388,7 +388,7 @@ class ProjectTarget (AbstractTarget): """ Generates all possible targets contained in this project. """ self.manager_.targets().log( - "Building project '%s' with '%s'" % (self.name (), ps.raw ())) + "Building project '%s' with '%s'" % (self.name (), str(ps))) self.manager_.targets().increase_indent () result = GenerateResult () @@ -656,14 +656,13 @@ class MainTarget (AbstractTarget): def apply_default_build (self, property_set): # 1. First, see what properties from default_build # are already present in property_set. - - raw = property_set.raw () - specified_features = get_grist (raw) + + specified_features = set(p.feature() for p in property_set.all()) defaults_to_apply = [] - for d in self.default_build_.raw (): - if not get_grist (d) in specified_features: - defaults_to_apply.append (d) + for d in self.default_build_.all(): + if not d.feature() in specified_features: + defaults_to_apply.append(d) # 2. If there's any defaults to be applied, form the new # build request. Pass it throw 'expand-no-defaults', since @@ -686,16 +685,9 @@ class MainTarget (AbstractTarget): # be an indication that # build_request.expand-no-defaults is the wrong rule # to use here. - compressed = feature.compress_subproperties (raw) + compressed = feature.compress_subproperties(property_set.all()) - properties = build_request.expand_no_defaults (compressed, defaults_to_apply) - - if properties: - for p in properties: - result.append (property_set.create (feature.expand (feature.split (p)))) - - else: - result .append (property_set.empty ()) + result = build_request.expand_no_defaults (compressed, defaults_to_apply) else: result.append (property_set) @@ -1042,8 +1034,8 @@ class BasicTarget (AbstractTarget): # is the object itself. This won't work in python. targets = [ self.manager_.register_object (x) for x in result.targets () ] - result_var += replace_grist (targets, grist) - usage_requirements += result.usage_requirements ().raw () + result_var += replace_grist(targets, grist) + usage_requirements += result.usage_requirements().all() return (result_var, usage_requirements) @@ -1078,7 +1070,7 @@ class BasicTarget (AbstractTarget): rproperties = self.common_properties (ps, self.requirements_) self.manager().targets().log( - "Common properties are '%s'" % str (rproperties.raw ())) + "Common properties are '%s'" % str (rproperties)) if rproperties.get("") != ["no"]: @@ -1096,11 +1088,13 @@ class BasicTarget (AbstractTarget): self.manager_.targets().log( "Usage requirements for '%s' are '%s'" % (self.name_, usage_requirements)) - rproperties = property_set.create (properties + usage_requirements) + # FIXME: + + rproperties = property_set.create(properties + [p.to_raw() for p in usage_requirements]) usage_requirements = property_set.create (usage_requirements) self.manager_.targets().log( - "Build properties: '%s'" % str(rproperties.raw())) + "Build properties: '%s'" % str(rproperties)) extra = rproperties.get ('') source_targets += replace_grist (extra, '') @@ -1251,7 +1245,7 @@ class TypedTarget (BasicTarget): def construct (self, name, source_targets, prop_set): r = generators.construct (self.project_, name, self.type_, - property_set.create (prop_set.raw () + ['' + self.type_]), + prop_set.add_raw(['' + self.type_]), source_targets) if not r: diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 5ef3a49b7..d042d9676 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -612,6 +612,9 @@ class FileTarget (AbstractFileTarget): self.path_ = path + def __str__(self): + return self.name_ + "." + self.type_ + def clone_with_different_type(self, new_type): return FileTarget(self.name_, new_type, self.project_, self.action_, self.path_, exact=True) @@ -764,7 +767,7 @@ class Action: toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties) engine = self.manager_.engine () - + self.manager_.engine ().set_update_action (self.action_name_, actual_targets, self.actual_sources_, properties) diff --git a/v2/build_system.py b/v2/build_system.py index 57f41cff8..1602d5b2e 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -128,7 +128,6 @@ def actual_clean_targets(targets): if isinstance(t, b2.build.targets.ProjectTarget): project_targets.append(t.project_module()) - # Construct a list of targets explicitly detected on this build system run # as a result of building main targets. targets_to_clean = set() @@ -594,16 +593,8 @@ def main_real(): virtual_targets = [] - # Virtual targets obtained when building main targets references on - # the command line. When running - # - # bjam --clean main_target - # - # we want to clean the files that belong only to that main target, - # so we need to record which targets are produced. - results_of_main_targets = [] + global results_of_main_targets - # Now that we have a set of targets to build and a set of property sets to # build the targets with, we can start the main build process by using each # property set to generate virtual targets from all of our listed targets @@ -849,7 +840,7 @@ def main_real(): bjam.call("UPDATE", "clean") else: # FIXME: - #configure.print-configure-checks-summary ; + #configure.print-configure-checks-summary ; if pre_build_hook: pre_build_hook() diff --git a/v2/tools/gcc.py b/v2/tools/gcc.py index 3b280e3d9..fa1ce387e 100644 --- a/v2/tools/gcc.py +++ b/v2/tools/gcc.py @@ -378,7 +378,7 @@ class GccLinkingGenerator(unix.UnixLinkingGenerator): property while creating or using shared library, since it's not supported by gcc/libc. """ - def run(self, project, name, prop_set, sources): + def run(self, project, name, ps, sources): # TODO: Replace this with the use of a target-os property. no_static_link = False @@ -392,10 +392,9 @@ class GccLinkingGenerator(unix.UnixLinkingGenerator): ## } ## } - properties = prop_set.raw() reason = None - if no_static_link and 'static' in properties: - if 'shared' in properties: + if no_static_link and ps.get('runtime-link') == 'static': + if ps.get('link') == 'shared': reason = "On gcc, DLL can't be build with 'static'." elif type.is_derived(self.target_types[0], 'EXE'): for s in sources: @@ -411,7 +410,7 @@ class GccLinkingGenerator(unix.UnixLinkingGenerator): return else: generated_targets = unix.UnixLinkingGenerator.run(self, project, - name, prop_set, sources) + name, ps, sources) return generated_targets if on_windows(): From 5129fe6fa2de3daea75dcff1351c96bfc5479c3e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 27 Jul 2010 11:53:37 +0000 Subject: [PATCH 055/165] Make default build work. Also, return non-zero status if there were errors. [SVN r64384] --- v2/build/errors.py | 5 +++++ v2/build/targets.py | 11 ++++++++--- v2/build_system.py | 11 +++++++++-- v2/kernel/bootstrap.jam | 6 +++++- v2/kernel/bootstrap.py | 2 +- v2/test/default_build.py | 3 ++- 6 files changed, 30 insertions(+), 8 deletions(-) diff --git a/v2/build/errors.py b/v2/build/errors.py index 83b39e982..8e17a73c0 100644 --- a/v2/build/errors.py +++ b/v2/build/errors.py @@ -97,6 +97,10 @@ class Errors: def __init__(self): self.contexts_ = [] + self._count = 0 + + def count(self): + return self._count def push_user_context(self, message, nested=None): self.contexts_.append(Context(message, nested)) @@ -117,6 +121,7 @@ class Errors: raise ExceptionWithUserContext("unexpected exception", self.contexts_[:], e, sys.exc_info()[2]) def __call__(self, message): + self._count = self._count + 1 raise ExceptionWithUserContext(message, self.contexts_[:], stack=traceback.extract_stack()) diff --git a/v2/build/targets.py b/v2/build/targets.py index 39b127a5c..918c23fd6 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -76,6 +76,8 @@ import re import os.path import sys +from b2.manager import get_manager + from b2.util.utility import * import property, project, virtual_target, property_set, feature, generators, toolset from virtual_target import Subvariant @@ -84,6 +86,8 @@ from b2.util.sequence import unique from b2.util import path, bjam_signature from b2.build.errors import user_error_checkpoint +import b2.build.build_request as build_request + import b2.util.set _re_separate_target_from_properties = re.compile (r'^([^<]*)(/(<.*))?$') @@ -594,10 +598,10 @@ class MainTarget (AbstractTarget): d = target.default_build () if self.alternatives_ and self.default_build_ != d: - raise BaseException ("Default build must be identical in all alternatives\n" + get_manager().errors()("default build must be identical in all alternatives\n" "main target is '%s'\n" "with '%s'\n" - "differing from previous default build: '%s'" % (full_name (), d.raw (), self.default_build_.raw ())) + "differing from previous default build: '%s'" % (self.full_name (), d.raw (), self.default_build_.raw ())) else: self.default_build_ = d @@ -687,7 +691,8 @@ class MainTarget (AbstractTarget): # to use here. compressed = feature.compress_subproperties(property_set.all()) - result = build_request.expand_no_defaults (compressed, defaults_to_apply) + result = build_request.expand_no_defaults( + b2.build.property_set.create([p]) for p in (compressed + defaults_to_apply)) else: result.append (property_set) diff --git a/v2/build_system.py b/v2/build_system.py index 1602d5b2e..5bc30c224 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -8,6 +8,8 @@ # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + from b2.build.engine import Engine from b2.manager import Manager from b2.util.path import glob @@ -432,14 +434,14 @@ def main(): if "--profiling" in sys.argv: import cProfile import pstats - cProfile.runctx('main_real()', globals(), locals(), "stones.prof") + return cProfile.runctx('main_real()', globals(), locals(), "stones.prof") stats = pstats.Stats("stones.prof") stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_callers(20) else: - main_real() + return main_real() def main_real(): @@ -852,3 +854,8 @@ def main_real(): # Prevent automatic update of the 'all' target, now that # we have explicitly updated what we wanted. bjam.call("UPDATE") + + if manager.errors().count() == 0: + return ["ok"] + else: + return [] diff --git a/v2/kernel/bootstrap.jam b/v2/kernel/bootstrap.jam index a629d214f..2a1be1a14 100644 --- a/v2/kernel/bootstrap.jam +++ b/v2/kernel/bootstrap.jam @@ -225,7 +225,11 @@ if ! $(dont-build) module PyBB { - bootstrap $(root) ; + local ok = [ bootstrap $(root) ] ; + if ! $(ok) + { + EXIT ; + } } diff --git a/v2/kernel/bootstrap.py b/v2/kernel/bootstrap.py index cc12add11..2e8dd37b7 100644 --- a/v2/kernel/bootstrap.py +++ b/v2/kernel/bootstrap.py @@ -21,5 +21,5 @@ def bootstrap(root_path): sys.modules["b2"] = m import b2.build_system - b2.build_system.main() + return b2.build_system.main() diff --git a/v2/test/default_build.py b/v2/test/default_build.py index 93d05ae3b..33f2b5bbb 100644 --- a/v2/test/default_build.py +++ b/v2/test/default_build.py @@ -42,7 +42,8 @@ with differing from previous default build debug """ -t.run_build_system("-n --no-error-backtrace", status=1, stdout=expected) +t.run_build_system("-n --no-error-backtrace", status=1) +t.fail_test(t.stdout().find("default build must be identical in all alternatives") == -1) # Test that default-build must be identical in all alternatives. No Error case, # empty default build. From 533adbeb3a6c78825300cc3af3937075749b9467 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 28 Jul 2010 12:04:31 +0000 Subject: [PATCH 056/165] More changes [SVN r64406] --- v2/build/engine.py | 5 ++- v2/build/generators.py | 4 +-- v2/build/property.py | 2 +- v2/build/property_set.py | 16 ++++----- v2/build/targets.py | 59 +++++++++++++++++++++------------- v2/build/virtual_target.py | 34 +++++++------------- v2/build_system.py | 2 +- v2/test/dependency-test/foo.py | 26 +++++++++++++++ v2/tools/builtin.py | 10 +++--- v2/tools/common.py | 4 +-- v2/tools/unix.py | 6 ++-- 11 files changed, 99 insertions(+), 69 deletions(-) create mode 100644 v2/test/dependency-test/foo.py diff --git a/v2/build/engine.py b/v2/build/engine.py index fb4f373d0..1fd70446c 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -8,6 +8,8 @@ bjam_interface = __import__('bjam') import operator +import b2.build.property_set as property_set + class BjamAction: """Class representing bjam action defined from Python.""" @@ -83,7 +85,7 @@ class Engine: for target in targets: self.do_set_target_variable (target, variable, value, append) - def set_update_action (self, action_name, targets, sources, properties): + def set_update_action (self, action_name, targets, sources, properties=property_set.empty()): """ Binds a target to the corresponding update action. If target needs to be updated, the action registered with action_name will be used. @@ -91,6 +93,7 @@ class Engine: either 'register_action' or 'register_bjam_action' method. """ + assert(isinstance(properties, property_set.PropertySet)) if isinstance (targets, str): targets = [targets] self.do_set_update_action (action_name, targets, sources, properties) diff --git a/v2/build/generators.py b/v2/build/generators.py index ab461f984..3709b9172 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -401,8 +401,8 @@ class Generator: name = self.determine_output_name(sources) # Assign an action for each target - action = self.action_class() - a = action (project.manager(), sources, self.id_, prop_set) + action = self.action_class() + a = action(project.manager(), sources, self.id_, prop_set) # Create generated target for each target type. targets = [] diff --git a/v2/build/property.py b/v2/build/property.py index 5eeea1a8a..c40fea879 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -44,7 +44,7 @@ class Property(object): return self._condition def to_raw(self): - result = "<" + self._feature.name() + ">" + self._value + result = "<" + self._feature.name() + ">" + str(self._value) if self._condition: result = ",".join(str(p) for p in self._condition) + ':' + result return result diff --git a/v2/build/property_set.py b/v2/build/property_set.py index dc3dcc32d..116e20813 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -34,7 +34,7 @@ def create (raw_properties = []): x = raw_properties else: x = [property.create_from_string(ps) for ps in raw_properties] - x.sort () + x.sort() x = unique (x) # FIXME: can we do better, e.g. by directly computing @@ -203,13 +203,7 @@ class PropertySet: pass else: self.base_raw_.append (p) - - if 'dependency' in att: - self.dependency_.append (p) - else: - self.non_dependency_.append (p) - - + if 'propagated' in att: self.propagated_.append (p) @@ -230,6 +224,12 @@ class PropertySet: else: self.non_conditional_.append(p) + if p.feature().dependency(): + self.dependency_.append (p) + else: + self.non_dependency_.append (p) + + def all(self): return self.all_ diff --git a/v2/build/targets.py b/v2/build/targets.py index 918c23fd6..a69450303 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -240,6 +240,7 @@ class GenerateResult: self.__usage_requirements = ur self.__targets = targets + assert all(isinstance(t, virtual_target.VirtualTarget) for t in targets) if not self.__usage_requirements: self.__usage_requirements = property_set.empty () @@ -1018,31 +1019,41 @@ class BasicTarget (AbstractTarget): else: return None + + + def generate_dependency_targets (self, target_ids, property_set): + targets = [] + usage_requirements = [] + for id in target_ids: + + result = self.generate_from_reference(id, self.project_, property_set) + targets += result.targets() + usage_requirements += result.usage_requirements().all() + + return (targets, usage_requirements) - def generate_dependencies (self, dependencies, property_set): + def generate_dependency_properties(self, properties, ps): """ Takes a target reference, which might be either target id or a dependency property, and generates that target using 'property_set' as build request. Returns a tuple (result, usage_requirements). """ - result_var = [] + result_properties = [] usage_requirements = [] - for dependency in dependencies: - grist = get_grist (dependency) - id = replace_grist (dependency, '') - - result = self.generate_from_reference (id, self.project_, property_set) + for p in properties: + + result = self.generate_from_reference(p.value(), self.project_, ps) - # FIXME: - # TODO: this is a problem: the grist must be kept and the value - # is the object itself. This won't work in python. - targets = [ self.manager_.register_object (x) for x in result.targets () ] + for t in result.targets(): + result_properties.append(property.Property(p.feature(), t)) - result_var += replace_grist(targets, grist) usage_requirements += result.usage_requirements().all() - return (result_var, usage_requirements) + return (result_properties, usage_requirements) + + + @user_error_checkpoint def generate (self, ps): @@ -1083,19 +1094,20 @@ class BasicTarget (AbstractTarget): properties = rproperties.non_dependency () - (p, u) = self.generate_dependencies (rproperties.dependency (), rproperties) + (p, u) = self.generate_dependency_properties (rproperties.dependency (), rproperties) properties += p + assert all(isinstance(p, property.Property) for p in properties) usage_requirements = u - (source_targets, u) = self.generate_dependencies (self.sources_, rproperties) + (source_targets, u) = self.generate_dependency_targets (self.sources_, rproperties) usage_requirements += u self.manager_.targets().log( "Usage requirements for '%s' are '%s'" % (self.name_, usage_requirements)) # FIXME: - - rproperties = property_set.create(properties + [p.to_raw() for p in usage_requirements]) + + rproperties = property_set.create(properties + usage_requirements) usage_requirements = property_set.create (usage_requirements) self.manager_.targets().log( @@ -1128,7 +1140,7 @@ class BasicTarget (AbstractTarget): self.manager_.targets().log ( "Usage requirements from '%s' are '%s'" % - (self.name, str(rproperties.raw()))) + (self.name(), str(rproperties))) self.generated_[ps] = GenerateResult (ur, result) else: @@ -1159,14 +1171,14 @@ class BasicTarget (AbstractTarget): project: Project where the reference is made property_set: Properties of the main target that makes the reference """ - target, sproperties = self.resolve_reference (target_reference, project) + target, sproperties = self.resolve_reference(target_reference, project) # Take properties which should be propagated and refine them # with source-specific requirements. - propagated = property_set.propagated () - rproperties = propagated.refine (sproperties) + propagated = property_set.propagated() + rproperties = propagated.refine(sproperties) - return target.generate (rproperties) + return target.generate(rproperties) def compute_usage_requirements (self, subvariant): """ Given the set of generated targets, and refined build @@ -1179,7 +1191,7 @@ class BasicTarget (AbstractTarget): # We generate all dependency properties and add them, # as well as their usage requirements, to result. - (r1, r2) = self.generate_dependencies (xusage_requirements.dependency (), rproperties) + (r1, r2) = self.generate_dependency_properties(xusage_requirements.dependency (), rproperties) extra = r1 + r2 result = property_set.create (xusage_requirements.non_dependency () + extra) @@ -1249,6 +1261,7 @@ class TypedTarget (BasicTarget): return self.type_ def construct (self, name, source_targets, prop_set): + r = generators.construct (self.project_, name, self.type_, prop_set.add_raw(['' + self.type_]), source_targets) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index d042d9676..e8654cab0 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -71,6 +71,7 @@ from b2.util.sequence import unique from b2.tools import common from b2.exceptions import * import b2.build.type +import b2.build.property_set as property_set import type __re_starts_with_at = re.compile ('^@(.*)') @@ -133,9 +134,6 @@ class VirtualTargetRegistry: # TODO: Don't append if we found pre-existing target? self.recent_targets_.append(result) self.all_targets_.append(result) - - result.set_id(self.next_id_) - self.next_id_ = self.next_id_+1 return result @@ -159,10 +157,7 @@ class VirtualTargetRegistry: result = FileTarget (file, file_type, project, None, file_location) self.files_ [path] = result - - result.set_id(self.next_id_) - self.next_id_ = self.next_id_+1 - + return result def recent_targets(self): @@ -269,15 +264,6 @@ class VirtualTarget: """ return self.project_ - def set_id(self, id): - self.id_ = id - - def __hash__(self): - return self.id_ - - def __cmp__(self, other): - return self.id_ - other.id_ - def depends (self, d): """ Adds additional instances of 'VirtualTarget' that this one depends on. @@ -707,11 +693,15 @@ class Action: not establish dependency relationship, but should do everything else. """ def __init__ (self, manager, sources, action_name, prop_set): + assert(isinstance(prop_set, property_set.PropertySet)) self.sources_ = sources self.action_name_ = action_name if not prop_set: prop_set = property_set.empty() self.properties_ = prop_set + if not all(isinstance(v, VirtualTarget) for v in prop_set.get('implicit-dependency')): + import pdb + pdb.set_trace() self.manager_ = manager self.engine_ = self.manager_.engine () @@ -750,6 +740,7 @@ class Action: ps = self.properties () properties = self.adjust_properties (ps) + actual_targets = [] for i in self.targets (): @@ -767,14 +758,14 @@ class Action: toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties) engine = self.manager_.engine () - + self.manager_.engine ().set_update_action (self.action_name_, actual_targets, self.actual_sources_, properties) # Since we set up creating action here, we also set up # action for cleaning up self.manager_.engine ().set_update_action ('common.Clean', 'clean-all', - actual_targets, None) + actual_targets) return actual_targets @@ -826,6 +817,7 @@ class Action: # if we're building just hello ("bjam hello"), 'a.h' won't be # actualized unless we do it here. implicit = self.properties_.get("") + for i in implicit: i.actualize() @@ -957,13 +949,11 @@ class Subvariant: # Pre-compose the list of other dependency graphs, on which this one # depends - deps = build_properties.get ('') + deps = build_properties.get('') self.other_dg_ = [] for d in deps: - # FIXME: the property must have the actual object here, not a string. - value = replace_grist (d, '') - self.other_dg_.append (value.creating_subvariant ()) + self.other_dg_.append(d.creating_subvariant ()) self.other_dg_ = unique (self.other_dg_) diff --git a/v2/build_system.py b/v2/build_system.py index 5bc30c224..8741fa15d 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -838,7 +838,7 @@ def main_real(): bjam.call("UPDATE", "clean-all") elif clean: manager.engine().set_update_action("common.Clean", "clean", - actual_clean_targets(targets), None) + actual_clean_targets(targets)) bjam.call("UPDATE", "clean") else: # FIXME: diff --git a/v2/test/dependency-test/foo.py b/v2/test/dependency-test/foo.py new file mode 100644 index 000000000..e4277cc0e --- /dev/null +++ b/v2/test/dependency-test/foo.py @@ -0,0 +1,26 @@ +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003, 2005, 2010 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 bjam +import b2.build.type as type +import b2.build.generators as generators + +from b2.manager import get_manager + +type.register("FOO", ["foo"]) +generators.register_standard("foo.foo", ["FOO"], ["CPP", "H"]) + +def prepare_foo(targets, sources, properties): + + if properties.get('os') in ['windows', 'cygwin']: + bjam.call('set-target-variable', targets, "DECL", + "void __declspec(dllexport) foo(){}") + + pass + +get_manager().engine().register_action("foo.foo",\ +"""echo $(DECL:E="//")\n > $(<[1]) +echo "#include "\n > $(<[2]) +""", function=prepare_foo) diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index 44d203f3f..3ed0e950c 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -659,15 +659,12 @@ class LinkingGenerator (generators.Generator): # sources to pass to inherited rule sources2 = [] - # properties to pass to inherited rule - properties2 = [] # sources which are libraries libraries = [] # Searched libraries are not passed as argument to linker # but via some option. So, we pass them to the action # via property. - properties2 = prop_set.raw() fsa = [] fst = [] for s in sources: @@ -682,12 +679,13 @@ class LinkingGenerator (generators.Generator): else: sources2.append(s) + add = [] if fsa: - properties2 += [replace_grist('&&'.join(fsa), '')] + add.append("" + '&&'.join(fsa)) if fst: - properties2 += [replace_grist('&&'.join(fst), '')] + add.append("" + '&&'.join(fst)) - spawn = generators.Generator.generated_targets(self, sources2, property_set.create(properties2), project, name) + spawn = generators.Generator.generated_targets(self, sources2,prop_set.add_raw(add), project, name) return spawn diff --git a/v2/tools/common.py b/v2/tools/common.py index 8de091f54..b0224b1b2 100644 --- a/v2/tools/common.py +++ b/v2/tools/common.py @@ -535,9 +535,9 @@ def mkdir(engine, target): # Schedule the mkdir build action. if os_name() == 'NT': - engine.set_update_action("common.MkDir1-quick-fix-for-windows", target, [], None) + engine.set_update_action("common.MkDir1-quick-fix-for-windows", target, []) else: - engine.set_update_action("common.MkDir1-quick-fix-for-unix", target, [], None) + engine.set_update_action("common.MkDir1-quick-fix-for-unix", target, []) # Prepare a Jam 'dirs' target that can be used to make the build only # construct all the target directories. diff --git a/v2/tools/unix.py b/v2/tools/unix.py index 025391d2d..d409c2e46 100644 --- a/v2/tools/unix.py +++ b/v2/tools/unix.py @@ -129,9 +129,9 @@ def set_library_order_aux (from_libs, to_libs): def set_library_order (manager, sources, prop_set, result): used_libraries = [] deps = prop_set.dependency () - - [ sources.append (manager.get_object (get_value (x))) for x in deps ] - sources = sequence.unique (sources) + + sources.extend(d.value() for d in deps) + sources = sequence.unique(sources) for l in sources: if l.type () and type.is_derived (l.type (), 'LIB'): From 6a297c38326ef1f9274fed1ab16d5bf182c34954 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 28 Jul 2010 12:27:08 +0000 Subject: [PATCH 057/165] Fix header dependencies processing. [SVN r64407] --- v2/build/scanner.py | 2 +- v2/kernel/bootstrap.jam | 4 +++- v2/tools/builtin.py | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/v2/build/scanner.py b/v2/build/scanner.py index fdb0addcf..19f1431d4 100644 --- a/v2/build/scanner.py +++ b/v2/build/scanner.py @@ -116,7 +116,7 @@ class CommonScanner(Scanner): bjam.call("mark-included", target, matches) get_manager().engine().set_target_variable(matches, "SEARCH", - [target_path] + self.includes) + [target_path] + self.includes) get_manager().scanners().propagate(self, matches) class ScannerRegistry: diff --git a/v2/kernel/bootstrap.jam b/v2/kernel/bootstrap.jam index 2a1be1a14..a3a5952d7 100644 --- a/v2/kernel/bootstrap.jam +++ b/v2/kernel/bootstrap.jam @@ -216,7 +216,9 @@ if ! $(dont-build) } rule mark-included ( targets * : includes * ) { - INCLUDES $(targets) : $(INCLUDES) ; + NOCARE $(includes) ; + INCLUDES $(targets) : $(includes) ; + ISFILE $(includes) ; } } diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index 3ed0e950c..5fd28e229 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -379,8 +379,8 @@ class CScanner (scanner.Scanner): bjam.call("mark-included", target, all) engine = get_manager().engine() - engine.set_target_variable(angle, "SEARCH", self.includes_) - engine.set_target_variable(quoted, "SEARCH", self.includes_) + engine.set_target_variable(angle, "SEARCH", get_value(self.includes_)) + engine.set_target_variable(quoted, "SEARCH", get_value(self.includes_)) # Just propagate current scanner to includes, in a hope # that includes do not change scanners. From fff46f1dc3aee9e437ac07f7a544af9c2baef734 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 28 Jul 2010 12:39:39 +0000 Subject: [PATCH 058/165] More header dependencies fixes [SVN r64408] --- v2/test/dependency-test/foo.py | 4 ++-- v2/tools/builtin.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/v2/test/dependency-test/foo.py b/v2/test/dependency-test/foo.py index e4277cc0e..f807bf4fa 100644 --- a/v2/test/dependency-test/foo.py +++ b/v2/test/dependency-test/foo.py @@ -21,6 +21,6 @@ def prepare_foo(targets, sources, properties): pass get_manager().engine().register_action("foo.foo",\ -"""echo $(DECL:E="//")\n > $(<[1]) -echo "#include "\n > $(<[2]) +"""echo -e $(DECL:E="//")\\n > $(<[1]) +echo -e "#include \\n" > $(<[2]) """, function=prepare_foo) diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index 5fd28e229..decad8501 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -380,7 +380,7 @@ class CScanner (scanner.Scanner): engine = get_manager().engine() engine.set_target_variable(angle, "SEARCH", get_value(self.includes_)) - engine.set_target_variable(quoted, "SEARCH", get_value(self.includes_)) + engine.set_target_variable(quoted, "SEARCH", [b] + get_value(self.includes_)) # Just propagate current scanner to includes, in a hope # that includes do not change scanners. @@ -388,6 +388,7 @@ class CScanner (scanner.Scanner): scanner.register (CScanner, 'include') type.set_scanner ('CPP', CScanner) +type.set_scanner ('C', CScanner) # Ported to trunk@47077 class LibGenerator (generators.Generator): From cd716b1e98fe55208a7e3772257d62f72142872a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 05:35:32 +0000 Subject: [PATCH 059/165] Various fixes [SVN r64426] --- v2/build/generators.py | 6 +++--- v2/build/project.py | 4 ++-- v2/build/targets.py | 6 +++--- v2/build/toolset.py | 14 ++++++++++++++ v2/engine/src/builtins.c | 7 +++++++ v2/engine/src/jam.c | 3 +++ v2/test/dll_path.py | 40 ++++++++++++++++++++++++++++++++++++++++ v2/tools/make.py | 6 +++++- 8 files changed, 77 insertions(+), 9 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index 3709b9172..d2106033e 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -138,7 +138,7 @@ class Generator: NOTE: all subclasses must have a similar signature for clone to work! """ - def __init__ (self, id, composing, source_types, target_types_and_names, requirements): + def __init__ (self, id, composing, source_types, target_types_and_names, requirements = []): assert(not isinstance(source_types, str)) assert(not isinstance(target_types_and_names, str)) self.id_ = id @@ -215,7 +215,7 @@ class Generator: self.requirements_) - def id (self): + def id(self): return self.id_ def source_types (self): @@ -547,7 +547,7 @@ def find (id): def register (g): """ Registers new generator instance 'g'. """ - id = g.id () + id = g.id() __generators [id] = g diff --git a/v2/build/project.py b/v2/build/project.py index a772edc41..9c63f4fd4 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -811,14 +811,14 @@ class ProjectRules: def add_rule_for_type(self, type): - rule_name = type.lower(); + rule_name = type.lower().replace("_", "-") def xpto (name, sources, requirements = [], default_build = None, usage_requirements = []): return self.manager_.targets().create_typed_target( type, self.registry.current(), name[0], sources, requirements, default_build, usage_requirements) - self.add_rule(type.lower(), xpto) + self.add_rule(rule_name, xpto) def add_rule(self, name, callable): self.rules[name] = callable diff --git a/v2/build/targets.py b/v2/build/targets.py index a69450303..33327cf7f 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -855,13 +855,13 @@ class BasicTarget (AbstractTarget): sproperties = [] if split.group (3): - sproperties = property.make (feature.split (split.group (3))) - sproperties = self.manager.features ().expand_composites (sproperties) + sproperties = property.create_from_strings(feature.split(split.group(3))) + sproperties = feature.expand_composites(sproperties) # Find the target target = project.find (id) - return (target, property_set.create (sproperties)) + return (target, property_set.create(sproperties)) def common_properties (self, build_request, requirements): """ Given build request and requirements, return properties diff --git a/v2/build/toolset.py b/v2/build/toolset.py index a63404cd4..3ffaff0cc 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -15,6 +15,7 @@ import b2.util.set from b2.util import cached from b2.util.utility import * from b2.util import bjam_signature +from b2.manager import get_manager __re_split_last_segment = re.compile (r'^(.+)\.([^\.])*') __re_two_ampersands = re.compile ('(&&)') @@ -114,6 +115,19 @@ def flags(rule_or_module, variable_name, condition, values = []): is specified, then the value of 'feature' will be added. """ + caller = bjam.caller() + if not '.' in rule_or_module and caller.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? + # Probably, 'flags' rule should be split into 'flags' and + # 'flags-on-module'. + rule_or_module = caller + rule_or_module + else: + # FIXME: revive checking that we don't set flags for a different + # module unintentionally + pass + if condition and not replace_grist (condition, ''): # We have condition in the form '', that is, without # value. That's a previous syntax: diff --git a/v2/engine/src/builtins.c b/v2/engine/src/builtins.c index 39c8a7821..29c6d9fb2 100644 --- a/v2/engine/src/builtins.c +++ b/v2/engine/src/builtins.c @@ -2078,6 +2078,13 @@ PyObject * bjam_backtrace( PyObject * self, PyObject * args ) return result; } +PyObject * bjam_caller( PyObject * self, PyObject * args ) +{ + PyObject *result = PyString_FromString( + frame_before_python_call->prev->module->name); + return result; +} + #endif /* #ifdef HAVE_PYTHON */ diff --git a/v2/engine/src/jam.c b/v2/engine/src/jam.c index f76546d8e..a4a150c3c 100644 --- a/v2/engine/src/jam.c +++ b/v2/engine/src/jam.c @@ -208,6 +208,7 @@ int anyhow = 0; extern PyObject * bjam_define_action( PyObject * self, PyObject * args ); extern PyObject * bjam_variable ( PyObject * self, PyObject * args ); extern PyObject * bjam_backtrace ( PyObject * self, PyObject * args ); + extern PyObject * bjam_caller ( PyObject * self, PyObject * args ); #endif char *saved_argv0; @@ -349,6 +350,8 @@ int main( int argc, char * * argv, char * * arg_environ ) "Obtains a variable from bjam's global module."}, {"backtrace", bjam_backtrace, METH_VARARGS, "Returns bjam backtrace from the last call into Python."}, + {"caller", bjam_caller, METH_VARARGS, + "Returns the module from which the last call into Python is made."}, {NULL, NULL, 0, NULL} }; diff --git a/v2/test/dll_path.py b/v2/test/dll_path.py index a02b2b04e..284b80207 100644 --- a/v2/test/dll_path.py +++ b/v2/test/dll_path.py @@ -81,6 +81,46 @@ rule list ( target : sources * : properties * ) } """) +t.write("dll_paths.py", """ +import bjam + +import b2.build.type as type +import b2.build.generators as generators + +from b2.manager import get_manager + +def init(): + type.register("PATH_LIST", ["pathlist"]) + + class DllPathsListGenerator(generators.Generator): + + def __init__(self): + generators.Generator.__init__(self, "dll_paths.list", False, ["EXE"], ["PATH_LIST"]) + + def generated_targets(self, sources, ps, project, name): + + dll_paths = [] + for s in sources: + a = s.action() + if a: + p = a.properties() + dll_paths += p.get('dll-path') + dll_paths.sort() + return generators.Generator.generated_targets(self, + sources, ps.add_raw(["" + p for p in dll_paths]), + project, name) + + generators.register(DllPathsListGenerator()) + +command = \"\"\" +echo $(PATHS) > $(<[1]) +\"\"\" +def function(target, sources, ps): + bjam.call('set-target-variable', target, "PATHS", ps.get('dll-path')) + +get_manager().engine().register_action("dll_paths.list", command, function=function) +""") + t.write("a/a.cpp", """ void #if defined(_WIN32) diff --git a/v2/tools/make.py b/v2/tools/make.py index a6d476269..391c1380d 100644 --- a/v2/tools/make.py +++ b/v2/tools/make.py @@ -25,7 +25,7 @@ class MakeTarget(BasicTarget): def construct(self, name, source_targets, property_set): action_name = property_set.get("")[0] - assert action_name[0] == '@' + (jamfile, rule) = _extract_jamfile_and_rule.match(action_name).groups() # This is very bad. We need to call rule inside the proper module, # not at global scope, where it might not be available at all. @@ -42,11 +42,15 @@ def make (target_name, sources, generating_rule, target_name = target_name[0] generating_rule = generating_rule[0] + if generating_rule[0] != '@': + generating_rule = '@' + generating_rule if not requirements: requirements = [] + requirements.append("%s" % generating_rule) + m = get_manager() targets = m.targets() project = m.projects().current() From 988307937e13933ff104f8a74c4057a838b6146b Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 07:33:02 +0000 Subject: [PATCH 060/165] Fix requesting specific files on the command line [SVN r64427] --- v2/build/project.py | 2 ++ v2/build/targets.py | 2 +- v2/build_system.py | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 9c63f4fd4..8202f8a08 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -214,6 +214,8 @@ class ProjectRegistry: if not project_module in self.jamfile_modules and \ b2.util.path.glob([location], self.JAMROOT + self.JAMFILE): project_module = self.load(location) + else: + project_module = None return project_module diff --git a/v2/build/targets.py b/v2/build/targets.py index 33327cf7f..4d327a044 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -738,7 +738,7 @@ class MainTarget (AbstractTarget): "Failed to build '%s'\n" "with properties '%s'\n" "because no best-matching alternative could be found." - % (full_name, prop_set.raw ())) + % (self.full_name(), prop_set)) result = best_alternative.generate (prop_set) diff --git a/v2/build_system.py b/v2/build_system.py index 8741fa15d..93ecd651a 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -551,6 +551,8 @@ def main_real(): virtual_targets = [] actual_targets = [] + explicitly_requested_files = [] + # Process each target specified on the command-line and convert it into # internal Boost Build target objects. Detect special clean target. If no # main Boost Build targets were explictly requested use the current project @@ -568,7 +570,7 @@ def main_real(): if not t: print "notice: could not find main target '%s'" % id print "notice: assuming it's a name of file to create " ; - bjam_targets.append(id) + explicitly_requested_files.append(id) else: targets.append(t) From 50645c9d24843327c1899ccc171cb325167f2b96 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 08:26:44 +0000 Subject: [PATCH 061/165] Update virtual_target.py [SVN r64428] --- v2/build/virtual_target.py | 45 +++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index e8654cab0..6d1634902 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -1,6 +1,5 @@ -# Status: being ported by Vladimir Prus -# Essentially ported, minor fixme remain. -# Base revision: 40480 +# Status: ported. +# Base revision: 64427. # # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and # distribute this software is granted provided this copyright notice appears in @@ -61,6 +60,8 @@ # but in builtin.jam modules. They are shown in the diagram to give # the big picture. +import bjam + import re import os.path import string @@ -122,8 +123,10 @@ class VirtualTargetRegistry: if a1 and a2 and a1.action_name () == a2.action_name () and a1.sources () == a2.sources (): ps1 = a1.properties () ps2 = a2.properties () - p1 = ps1.base () + ps1.free () + ps1.dependency () - p2 = ps2.base () + ps2.free () + ps2.dependency () + p1 = ps1.base () + ps1.free () +\ + b2.util.set.difference(ps1.dependency(), ps1.incidental()) + p2 = ps2.base () + ps2.free () +\ + b2.util.set.difference(ps2.dependency(), ps2.incidental()) if p1 == p2: result = t @@ -244,6 +247,7 @@ class VirtualTarget: self.name_ = name self.project_ = project self.dependencies_ = [] + self.always_ = False # Caches if dapendencies for scanners have already been set. self.made_ = {} @@ -273,6 +277,9 @@ class VirtualTarget: def dependencies (self): return self.dependencies_ + def always(self): + self.always_ = True + def actualize (self, scanner = None): """ Generates all the actual targets and sets up build actions for this target. @@ -287,6 +294,9 @@ class VirtualTarget: """ actual_name = self.actualize_no_scanner () + if self.always_: + bjam.call("ALWAYS", actual_name) + if not scanner: return actual_name @@ -644,6 +654,11 @@ class FileTarget (AbstractFileTarget): # for test.o will be test.o and the target # we create below will be test.o engine.add_dependency("%s" % get_value(target), target) + + # Allow bjam / to work. This won't catch all + # possible ways to refer to the path (relative/absolute, extra ".", + # various "..", but should help in obvious cases. + engine.add_dependency("%s" % (os.path.join(path, get_value(target))), target) else: # This is a source file. @@ -682,6 +697,7 @@ class NotFileTarget(AbstractFileTarget): def actualize_location(self, target): bjam.call("NOTFILE", target) bjam.call("ALWAYS", taget) + bjam.call("NOUPDATE", target) class Action: @@ -717,6 +733,10 @@ class Action: def add_targets (self, targets): self.targets_ += targets + + def replace_targets (old_targets, new_targets): + self.targets_ = [t for t in targets if not t in old_targets] + new_targets + def targets (self): return self.targets_ @@ -758,6 +778,11 @@ class Action: toolset.set_target_variables (self.manager_, self.action_name_, actual_targets, properties) engine = self.manager_.engine () + + # FIXME: this is supposed to help --out-xml option, but we don't + # implement that now, and anyway, we should handle it in Python, + # not but putting variables on bjam-level targets. + bjam.call("set-target-variable", actual_targets, ".action", repr(self)) self.manager_.engine ().set_update_action (self.action_name_, actual_targets, self.actual_sources_, properties) @@ -981,7 +1006,7 @@ class Subvariant: def usage_requirements (self): return self.usage_requirements_ - def all_referenced_targets(self): + def all_referenced_targets(self, result): """Returns all targets referenced by this subvariant, either directly or indirectly, and either as sources, or as dependency properties. Targets referred with @@ -994,14 +1019,14 @@ class Subvariant: # Find other subvariants. r = [] for t in all_targets: - r.append(t.creating_subvariant) + if not t in result: + result.add(t) + r.append(t.creating_subvariant) r = unique(r) - for s in r: if s != self: - all_targets.extend(s.all_referenced_targets()) + s.all_referenced_targets(result) - return all_targets def implicit_includes (self, feature, target_type): """ Returns the properties which specify implicit include paths to From 544d47f9b69840450dace3f28e59e15cde5e751c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 08:27:49 +0000 Subject: [PATCH 062/165] Don't pass None for property set [SVN r64429] --- v2/tools/gcc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/tools/gcc.py b/v2/tools/gcc.py index fa1ce387e..4f171d65f 100644 --- a/v2/tools/gcc.py +++ b/v2/tools/gcc.py @@ -624,7 +624,7 @@ def gcc_archive(targets, sources, properties): engine.set_target_variable('LOCATE', clean, bjam.call('get-target-variable', targets, 'LOCATE')) engine.add_dependency(clean, sources) engine.add_dependency(targets, clean) - engine.set_update_action('common.RmTemps', clean, targets, None) + engine.set_update_action('common.RmTemps', clean, targets) # Declare action for creating static libraries. # The letter 'r' means to add files to the archive with replacement. Since we From 6d9d4fcfceb8ed5df301de7cea0bb48638894ad1 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 10:39:31 +0000 Subject: [PATCH 063/165] Port notfile.py. Attempt to clean the mess with decorating action names. [SVN r64431] --- v2/build/engine.py | 17 ++++++++++--- v2/build/project.py | 2 +- v2/build/property.py | 10 ++++++-- v2/build/targets.py | 16 ++++++++++++ v2/build/virtual_target.py | 19 +++++++++----- v2/kernel/bootstrap.jam | 8 ++++++ v2/test/BoostBuild.py | 2 +- v2/test/notfile.py | 2 +- v2/tools/make.py | 13 ++-------- v2/tools/notfile.py | 51 ++++++++++++++++++++++++++++++++++++++ 10 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 v2/tools/notfile.py diff --git a/v2/build/engine.py b/v2/build/engine.py index 1fd70446c..2c98e2fb1 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -7,9 +7,12 @@ bjam_interface = __import__('bjam') import operator +import re import b2.build.property_set as property_set +_extract_jamfile_and_rule = re.compile("@(Jamfile<.*>)%(.*)") + class BjamAction: """Class representing bjam action defined from Python.""" @@ -20,6 +23,7 @@ class BjamAction: 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. @@ -33,12 +37,19 @@ class BjamNativeAction: self.action_name = action_name def __call__(self, targets, sources, property_set): + p = [] if property_set: - bjam_interface.call("set-update-action", self.action_name, - targets, sources, property_set.raw()) + p = property_set.raw() + + # FIXME: whazzup? + m = None #_extract_jamfile_and_rule.match(self.action_name) + if m: + bjam_interface.call("set-update-action-in-module", + m.group(1), m.group(2), + targets, sources, p) else: bjam_interface.call("set-update-action", self.action_name, - targets, sources, []) + targets, sources, p) action_modifiers = {"updated": 0x01, "together": 0x02, diff --git a/v2/build/project.py b/v2/build/project.py index 8202f8a08..8cf714d7e 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -637,7 +637,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) mname = "__build_build_temporary__" file = open(location) - try: + try: # TODO: this means we'll never make use of .pyc module, # which might be a problem, or not. module = imp.load_module(mname, file, os.path.basename(location), diff --git a/v2/build/property.py b/v2/build/property.py index c40fea879..41b45b359 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -231,10 +231,16 @@ def translate_indirect(properties, context_module): # will conflict. m = context_module + "." + m - v = context_module + '%' + m + # FIXME: now sure if we should register name with '@' + # or without. + #v = '@' + context_module + '%' + m + #print "REGISTER", get_manager().engine().register_bjam_action(m) + ## FIXME: whatsup? + #get_manager().engine().register_bjam_action(v) + v = '@' + m - result.append(Property(p.feature(), "@" + v, p.condition())) + result.append(Property(p.feature(), v, p.condition())) else: result.append(p) diff --git a/v2/build/targets.py b/v2/build/targets.py index 4d327a044..f93651aaf 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -1281,6 +1281,22 @@ class TypedTarget (BasicTarget): return r + +def create_typed_metatarget(name, type, sources, requirements, default_build, usage_requirements): + + from b2.manager import get_manager + t = get_manager().targets() + + project = get_manager().projects().current() + + return t.main_target_alternative( + TypedTarget(name, project, type, + t.main_target_sources(sources, name), + t.main_target_requirements(requirements, project), + t.main_target_default_build(default_build, project), + t.main_target_usage_requirements(usage_requirements, project))) + + def metatarget_function_for_class(class_): @bjam_signature((["name"], ["sources", "*"], ["requirements", "*"], diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 6d1634902..25b672cc0 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -105,7 +105,10 @@ class VirtualTargetRegistry: and equal action. If such target is found it is retured and 'target' is not registered. Otherwise, 'target' is registered and returned. """ - signature = target.path() + "-" + target.name() + if target.path(): + signature = target.path() + "-" + target.name() + else: + signature = "-" + target.name() result = None if not self.cache_.has_key (signature): @@ -566,7 +569,9 @@ def add_prefix_and_suffix(specified_name, type, property_set): """Appends the suffix appropriate to 'type/property-set' combination to the specified name and returns the result.""" - suffix = b2.build.type.generated_target_suffix(type, property_set) + suffix = "" + if type: + suffix = b2.build.type.generated_target_suffix(type, property_set) # Handle suffixes for which no leading dot is desired. Those are # specified by enclosing them in <...>. Needed by python so it @@ -576,7 +581,9 @@ def add_prefix_and_suffix(specified_name, type, property_set): elif suffix: suffix = "." + suffix - prefix = b2.build.type.generated_target_prefix(type, property_set) + prefix = "" + if type: + prefix = b2.build.type.generated_target_prefix(type, property_set) if specified_name.startswith(prefix): prefix = "" @@ -687,8 +694,8 @@ class FileTarget (AbstractFileTarget): class NotFileTarget(AbstractFileTarget): - def __init__(self, name, project): - AbstractFileTarget.__init__(name, project) + def __init__(self, name, project, action): + AbstractFileTarget.__init__(self, name, None, project, action) def path(self): """Returns nothing, to indicate that target path is not known.""" @@ -696,7 +703,7 @@ class NotFileTarget(AbstractFileTarget): def actualize_location(self, target): bjam.call("NOTFILE", target) - bjam.call("ALWAYS", taget) + bjam.call("ALWAYS", target) bjam.call("NOUPDATE", target) diff --git a/v2/kernel/bootstrap.jam b/v2/kernel/bootstrap.jam index a3a5952d7..28ec57348 100644 --- a/v2/kernel/bootstrap.jam +++ b/v2/kernel/bootstrap.jam @@ -192,6 +192,14 @@ if ! $(dont-build) $(action) $(targets) : $(sources) : $(properties) ; } + rule set-update-action-in-module ( m : action : targets * : sources * : properties * ) + { + module $(m) + { + $(2) $(3) : $(4) : $(5) ; + } + } + rule set-target-variable ( targets + : variable : value * : append ? ) { if $(append) diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index 8c5024f15..e9756342e 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -261,7 +261,7 @@ class Tester(TestCmd.TestCmd): verbosity = ['-d+2'] if boost_build_path is None: - boost_build_path = self.original_workdir + boost_build_path = self.original_workdir + "/.." program_list = [] diff --git a/v2/test/notfile.py b/v2/test/notfile.py index c061326a9..f4db79665 100644 --- a/v2/test/notfile.py +++ b/v2/test/notfile.py @@ -38,7 +38,7 @@ t.fail_test(string.find(t.stdout(), "echo hi") == -1) name = t.adjust_names(["bin/$toolset/debug/hello.exe"])[0] name = apply(os.path.join, string.split(name, "/")); -c = "valgrind " + name +c = "valgrind *" + name t.expect_output_line(c) t.cleanup() diff --git a/v2/tools/make.py b/v2/tools/make.py index 391c1380d..10baa1cb4 100644 --- a/v2/tools/make.py +++ b/v2/tools/make.py @@ -16,22 +16,13 @@ from b2.build import type from b2.manager import get_manager import b2.build.property_set -# FIXME: copy-paste from generate.py -import re -_extract_jamfile_and_rule = re.compile("@(Jamfile<.*>)%(.*)") class MakeTarget(BasicTarget): def construct(self, name, source_targets, property_set): - action_name = property_set.get("")[0] - - (jamfile, rule) = _extract_jamfile_and_rule.match(action_name).groups() - # This is very bad. We need to call rule inside the proper module, - # not at global scope, where it might not be available at all. - action_name = rule - - action = Action(get_manager(), source_targets, action_name, property_set) + action_name = property_set.get("")[0] + action = Action(get_manager(), source_targets, action_name[1:], property_set) target = FileTarget(self.name(), type.type(self.name()), self.project(), action, exact=True) return [ b2.build.property_set.empty(), diff --git a/v2/tools/notfile.py b/v2/tools/notfile.py new file mode 100644 index 000000000..afbf68fb0 --- /dev/null +++ b/v2/tools/notfile.py @@ -0,0 +1,51 @@ +# Status: ported. +# Base revision: 64429. +# +# Copyright (c) 2005-2010 Vladimir Prus. +# +# Use, modification and distribution is subject to the Boost Software +# License Version 1.0. (See accompanying file LICENSE_1_0.txt or +# http://www.boost.org/LICENSE_1_0.txt) + + +import b2.build.type as type +import b2.build.generators as generators +import b2.build.virtual_target as virtual_target +import b2.build.toolset as toolset +import b2.build.targets as targets + +from b2.manager import get_manager +from b2.util import bjam_signature + +type.register("NOTFILE_MAIN") + +class NotfileGenerator(generators.Generator): + + def run(self, project, name, ps, sources): + pass + action_name = ps.get('action')[0] + if action_name[0] == '@': + action = virtual_target.Action(get_manager(), sources, action_name[1:], ps) + else: + action = virtual_target.Action(get_manager(), sources, "notfile.run", ps) + + return [get_manager().virtual_targets().register( + virtual_target.NotFileTarget(name, project, action))] + +generators.register(NotfileGenerator("notfile.main", False, [], ["NOTFILE_MAIN"])) + +toolset.flags("notfile.run", "ACTION", [], [""]) + +get_manager().engine().register_action("notfile.run", "$(ACTION)") + +@bjam_signature((["target_name"], ["action"], ["sources", "*"], ["requirements", "*"], + ["default_build", "*"])) +def notfile(target_name, action, sources, requirements, default_build): + + requirements.append("" + action) + + return targets.create_typed_metatarget(target_name, "NOTFILE_MAIN", sources, requirements, + default_build, []) + + +get_manager().projects().add_rule("notfile", notfile) From 38f35e969575f96a7b0d2f5cb26b36ab2b90cb51 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 11:37:07 +0000 Subject: [PATCH 064/165] Redo naming of actions again. Return values from Python to Jamfiles. [SVN r64432] --- v2/build/engine.py | 14 +++++++++++--- v2/build/project.py | 5 +++-- v2/build/property.py | 32 +++----------------------------- v2/build/toolset.py | 4 ++-- v2/engine/src/compile.c | 34 +++++----------------------------- v2/tools/common.py | 4 ++-- 6 files changed, 26 insertions(+), 67 deletions(-) diff --git a/v2/build/engine.py b/v2/build/engine.py index 2c98e2fb1..56d5c2728 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -11,7 +11,8 @@ import re import b2.build.property_set as property_set -_extract_jamfile_and_rule = re.compile("@(Jamfile<.*>)%(.*)") +_indirect_rule = re.compile("^([^%]*)%([^%]+)$") +_extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)") class BjamAction: """Class representing bjam action defined from Python.""" @@ -41,8 +42,7 @@ class BjamNativeAction: if property_set: p = property_set.raw() - # FIXME: whazzup? - m = None #_extract_jamfile_and_rule.match(self.action_name) + m = _extract_jamfile_and_rule.match(self.action_name) if m: bjam_interface.call("set-update-action-in-module", m.group(1), m.group(2), @@ -137,6 +137,14 @@ class Engine: self.actions[action_name] = BjamAction(action_name, function) + def qualify_bjam_action(self, action_name, context_module): + + if _indirect_rule.match(action_name): + # Rule is already in indirect format + return action_name + else: + return context_module + '%' + action_name + def register_bjam_action (self, action_name): """Informs self that 'action_name' is declared in bjam. diff --git a/v2/build/project.py b/v2/build/project.py index 8cf714d7e..62e5a1ae3 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -849,7 +849,7 @@ class ProjectRules: e.report() finally: self.manager_.errors().pop_jamfile_context() - + return result def make_wrapper(self, callable): @@ -857,7 +857,7 @@ class ProjectRules: callable that will call 'callable' and report all exceptins, using 'call_and_report_errors'.""" def wrapper(*args, **kw): - self.call_and_report_errors(callable, *args, **kw) + return self.call_and_report_errors(callable, *args, **kw) return wrapper def init_project(self, project_module): @@ -1011,6 +1011,7 @@ attribute is allowed only for top-level 'project' invocations""") for f in m.__dict__: v = m.__dict__[f] + f = f.replace("_", "-") if callable(v): self._import_rule(jamfile_module, name + "." + f, v) self.reverse.setdefault(jamfile_module, {})[name + "." + f] = v diff --git a/v2/build/property.py b/v2/build/property.py index 41b45b359..beea19cd4 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -21,7 +21,6 @@ __re_split_conditional = re.compile (r'(.+):<(.+)') __re_colon = re.compile (':') __re_has_condition = re.compile (r':<') __re_separate_condition_and_property = re.compile (r'(.*):(<.*)') -__re_indirect_rule = re.compile("^([^%]*)%([^%]+)$") class Property(object): @@ -213,34 +212,9 @@ def translate_indirect(properties, context_module): result = [] for p in properties: if p.value()[0] == '@': - v = None - m = p.value()[1:] - if __re_indirect_rule.match(m): - # Rule is already in indirect format - # FIXME: it's not clear if this is necessary. - v = m - else: - - if not '.' in m: - # This is unqualified rule name. The user might want - # to set flags on this rule name, and toolset.flag - # auto-qualifies the rule name. Need to do the same - # here so set flag setting work. - # We can arrange for toolset.flag to *not* auto-qualify - # the argument, but then two rules defined in two Jamfiles - # will conflict. - m = context_module + "." + m - - # FIXME: now sure if we should register name with '@' - # or without. - #v = '@' + context_module + '%' + m - #print "REGISTER", - get_manager().engine().register_bjam_action(m) - ## FIXME: whatsup? - #get_manager().engine().register_bjam_action(v) - v = '@' + m - - result.append(Property(p.feature(), v, p.condition())) + q = get_manager().engine().qualify_bjam_action(p.value()[1:], context_module) + get_manager().engine().register_bjam_action(q) + result.append(Property(p.feature(), '@' + q, p.condition())) else: result.append(p) diff --git a/v2/build/toolset.py b/v2/build/toolset.py index 3ffaff0cc..3ad356db3 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -115,14 +115,14 @@ def flags(rule_or_module, variable_name, condition, values = []): is specified, then the value of 'feature' will be added. """ - caller = bjam.caller() + caller = bjam.caller()[:-1] if not '.' in rule_or_module and caller.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? # Probably, 'flags' rule should be split into 'flags' and # 'flags-on-module'. - rule_or_module = caller + rule_or_module + rule_or_module = get_manager().engine().qualify_bjam_action(rule_or_module, caller) else: # FIXME: revive checking that we don't set flags for a different # module unintentionally diff --git a/v2/engine/src/compile.c b/v2/engine/src/compile.c index 7a3f8d258..a4106bf39 100644 --- a/v2/engine/src/compile.c +++ b/v2/engine/src/compile.c @@ -846,35 +846,9 @@ call_python_function(RULE* r, FRAME* frame) } } } - else if ( PyInstance_Check( py_result ) ) + else if (PyString_Check(py_result)) { - static char instance_name[1000]; - static char imported_method_name[1000]; - module_t * m; - PyObject * method; - PyObject * method_name = PyString_FromString("foo"); - RULE * r; - - fprintf(stderr, "Got instance!\n"); - - snprintf(instance_name, 1000, - "pyinstance%d", python_instance_number); - snprintf(imported_method_name, 1000, - "pyinstance%d.foo", python_instance_number); - ++python_instance_number; - - m = bindmodule(instance_name); - - /* This is expected to get bound method. */ - method = PyObject_GetAttr(py_result, method_name); - - r = bindrule( imported_method_name, root_module() ); - - r->python_function = method; - - result = list_new(0, newstr(instance_name)); - - Py_DECREF( method_name ); + result = list_new (0, newstr (PyString_AsString(py_result))); } else if ( py_result == Py_None ) { @@ -882,7 +856,9 @@ call_python_function(RULE* r, FRAME* frame) } else { - fprintf(stderr, "Non-list object returned by Python call\n"); + /* Do nothing. 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. */ } Py_DECREF( py_result ); diff --git a/v2/tools/common.py b/v2/tools/common.py index b0224b1b2..5fc855663 100644 --- a/v2/tools/common.py +++ b/v2/tools/common.py @@ -513,9 +513,9 @@ def file_creation_command(): already exists is unspecified. """ if os_name() == 'NT': - return "echo. > " + return ["echo. > "] else: - return "touch " + return ["touch "] #FIXME: global variable __mkdir_set = set() From fe5ee873004e5c5f7cfb7e61dd8dcba9fcd08a7e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 11:40:00 +0000 Subject: [PATCH 065/165] Fix expected status [SVN r64433] --- v2/test/build_dir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/test/build_dir.py b/v2/test/build_dir.py index ad5327979..c5bcbc5b9 100644 --- a/v2/test/build_dir.py +++ b/v2/test/build_dir.py @@ -99,7 +99,7 @@ exe a : a.cpp ; build-project sub ; """ % string.replace(os.getcwd(), '\\', '\\\\')) -t.run_build_system("--build-dir=build") +t.run_build_system("--build-dir=build", status=1) t.fail_test(string.find(t.stdout(), "Absolute directory specified via 'build-dir' project attribute") == -1) From 7c59fa4358ab340abfcdaa7c10fa92959143ae00 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 12:00:53 +0000 Subject: [PATCH 066/165] Port cast [SVN r64434] --- v2/tools/cast.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 v2/tools/cast.py diff --git a/v2/tools/cast.py b/v2/tools/cast.py new file mode 100644 index 000000000..8f053f110 --- /dev/null +++ b/v2/tools/cast.py @@ -0,0 +1,69 @@ +# Status: ported +# Base revision: 64432. +# Copyright 2005-2010 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) + +# Defines main target 'cast', used to change type for target. For example, in Qt +# library one wants two kinds of CPP files -- those that just compiled and those +# that are passed via the MOC tool. +# +# This is done with: +# +# exe main : main.cpp [ cast _ moccable-cpp : widget.cpp ] ; +# +# Boost.Build will assing 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. +# +# At the moment, the 'cast' rule only works for non-derived (source) targets. +# +# TODO: The following comment is unclear or incorrect. Clean it up. +# > Another solution would be to add a separate main target 'moc-them' that +# > would moc all the passed sources, no matter what their type is, but I prefer +# > cast, as defining a new target type + generator for that type is somewhat +# > simpler than defining a main target rule. + +import b2.build.targets as targets +import b2.build.virtual_target as virtual_target + +from b2.manager import get_manager +from b2.util import bjam_signature + +class CastTargetClass(targets.TypedTarget): + + def construct(name, source_targets, ps): + result = [] + for s in source_targets: + if not isinstance(s, virtual_targets.FileTarget): + get_manager().errors()("Source to the 'cast' metatager is not a file") + + if s.action(): + get_manager().errors()("Only non-derived targets allowed as sources for 'cast'.") + + + r = s.clone_with_different_type(self.type()) + result.append(get_manager().virtual_targets().register(r)) + + return result + + +@bjam_signature((["name", "type"], ["sources", "*"], ["requirements", "*"], + ["default_build", "*"], ["usage_requirements", "*"])) +def cast(name, type, sources, requirements, default_build, usage_requirements): + + from b2.manager import get_manager + t = get_manager().targets() + + project = get_manager().projects().current() + + return t.main_target_alternative( + CastTargetClass(name, project, type, + t.main_target_sources(sources, name), + t.main_target_requirements(requirements, project), + t.main_target_default_build(default_build, project), + t.main_target_usage_requirements(usage_requirements, project))) + + +get_manager().projects().add_rule("cast", cast) From 9531774f5a5448ff12adf7b8b30ed630693f09b8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 12:01:45 +0000 Subject: [PATCH 067/165] Fix project.find again [SVN r64435] --- v2/build/project.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 62e5a1ae3..554b55e1f 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -211,11 +211,11 @@ class ProjectRegistry: # must be placed in the directory referred by id. project_module = self.module_name(location) - if not project_module in self.jamfile_modules and \ - b2.util.path.glob([location], self.JAMROOT + self.JAMFILE): - project_module = self.load(location) - else: - project_module = None + if not project_module in self.jamfile_modules: + if b2.util.path.glob([location], self.JAMROOT + self.JAMFILE): + project_module = self.load(location) + else: + project_module = None return project_module From 6fafa45f50f83ec850c6db1ce81d1480e9873fad Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 29 Jul 2010 14:33:56 +0000 Subject: [PATCH 068/165] Add stub port of os.jam. [SVN r64444] --- v2/build/project.py | 5 ++++- v2/util/os_j.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 v2/util/os_j.py diff --git a/v2/build/project.py b/v2/build/project.py index 554b55e1f..87f609fe2 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -1003,11 +1003,14 @@ attribute is allowed only for top-level 'project' invocations""") def import_(self, name, names_to_import=None, local_names=None): name = name[0] + py_name = name + if py_name == "os": + py_name = "os_j" jamfile_module = self.registry.current().project_module() attributes = self.registry.attributes(jamfile_module) location = attributes.get("location") - m = self.registry.load_module(name, [location]) + m = self.registry.load_module(py_name, [location]) for f in m.__dict__: v = m.__dict__[f] diff --git a/v2/util/os_j.py b/v2/util/os_j.py new file mode 100644 index 000000000..6ad22b85b --- /dev/null +++ b/v2/util/os_j.py @@ -0,0 +1,16 @@ +# Status: stub, just enough to make tests work. +# +# Named os_j to avoid conflicts with standard 'os'. See +# project.py:import for special-casing. +# +# Copyright 2001, 2002, 2003, 2005 Dave Abrahams +# Copyright 2006 Rene Rivera +# Copyright 2003, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + + +import os + +def name(): + return os.name From 13d72d7bba237db31bcb44e2139465439fba8aa9 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 06:23:32 +0000 Subject: [PATCH 069/165] Update port of tools/types/lib.jam [SVN r64457] --- v2/tools/types/lib.py | 90 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/v2/tools/types/lib.py b/v2/tools/types/lib.py index 0bd3f5547..d0ec1fb52 100644 --- a/v2/tools/types/lib.py +++ b/v2/tools/types/lib.py @@ -1,23 +1,77 @@ -# Copyright David Abrahams 2004. Distributed under the Boost +# Status: ported +# Base revision: 64456. +# Copyright David Abrahams 2004. +# Copyright Vladimir Prus 2010. +# 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 +import b2.build.type as type -def register (): - - if not type.registered ('LIB'): - type.register ('LIB') - - type.register_type ('STATIC_LIB', ['lib', 'a'], 'LIB', ['NT', 'CYGWIN']) - type.register_type ('STATIC_LIB', ['a'], 'LIB') - - type.register_type ('IMPORT_LIB', [], 'STATIC_LIB') - type.set_generated_target_suffix ('IMPORT_LIB', [], 'lib') - - type.register_type ('SHARED_LIB', ['dll'], 'LIB', ['NT', 'CYGWIN']) - type.register_type ('SHARED_LIB', ['so'], 'LIB') - - type.register_type ('SEARCHED_LIB', [], 'LIB') +# The following naming scheme is used for libraries. +# +# On *nix: +# libxxx.a static library +# libxxx.so shared library +# +# On windows (msvc) +# libxxx.lib static library +# xxx.dll DLL +# xxx.lib import library +# +# On windows (mingw): +# libxxx.a static library +# libxxx.dll DLL +# libxxx.dll.a import library +# +# On cygwin i.e. cygwin +# libxxx.a static library +# cygxxx.dll DLL +# libxxx.dll.a import library +# -register () +type.register('LIB') + +# FIXME: should not register both extensions on both platforms. +type.register('STATIC_LIB', ['a', 'lib'], 'LIB') + +# The 'lib' prefix is used everywhere +type.set_generated_target_prefix('STATIC_LIB', [], 'lib') + +# Use '.lib' suffix for windows +type.set_generated_target_suffix('STATIC_LIB', ['windows'], 'lib') + +# Except with gcc. +type.set_generated_target_suffix('STATIC_LIB', ['gcc', 'windows'], 'a') + +# Use xxx.lib for import libs +type.register('IMPORT_LIB', [], 'STATIC_LIB') +type.set_generated_target_prefix('IMPORT_LIB', [], '') +type.set_generated_target_suffix('IMPORT_LIB', [], 'lib') + +# Except with gcc (mingw or cygwin), where use libxxx.dll.a +type.set_generated_target_prefix('IMPORT_LIB', ['gcc'], 'lib') +type.set_generated_target_suffix('IMPORT_LIB', ['gcc'], 'dll.a') + +type.register('SHARED_LIB', ['so', 'dll', 'dylib'], 'LIB') + +# Both mingw and cygwin use libxxx.dll naming scheme. +# On Linux, use "lib" prefix +type.set_generated_target_prefix('SHARED_LIB', [], 'lib') +# But don't use it on windows +type.set_generated_target_prefix('SHARED_LIB', ['windows'], '') +# But use it again on mingw +type.set_generated_target_prefix('SHARED_LIB', ['gcc', 'windows'], 'lib') +# And use 'cyg' on cygwin +type.set_generated_target_prefix('SHARED_LIB', ['cygwin'], 'cyg') + + +type.set_generated_target_suffix('SHARED_LIB', ['windows'], 'dll') +type.set_generated_target_suffix('SHARED_LIB', ['cygwin'], 'dll') +type.set_generated_target_suffix('SHARED_LIB', ['darwin'], 'dylib') + +type.register('SEARCHED_LIB', [], 'LIB') +# This is needed so that when we create a target of SEARCHED_LIB +# type, there's no prefix or suffix automatically added. +type.set_generated_target_prefix('SEARCHED_LIB', [], '') +type.set_generated_target_suffix('SEARCHED_LIB', [], '') From a1d797e78fe8029c2337c4a295a213c8359b24c5 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 07:38:13 +0000 Subject: [PATCH 070/165] Port tools/stage.jam. [SVN r64458] --- v2/build/property_set.py | 17 +- v2/build/targets.py | 15 +- v2/build/type.py | 5 +- v2/build/virtual_target.py | 48 +++-- v2/tools/builtin.py | 2 + v2/tools/stage.py | 349 +++++++++++++++++++++++++++++++++++++ 6 files changed, 410 insertions(+), 26 deletions(-) create mode 100644 v2/tools/stage.py diff --git a/v2/build/property_set.py b/v2/build/property_set.py index 116e20813..e77273510 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -366,7 +366,7 @@ class PropertySet: # change the location of generated targets l = self.get ('') if l: - computed = l + computed = l[0] is_relative = False else: @@ -394,7 +394,7 @@ class PropertySet: is_relative = True self.target_path_ = (computed, is_relative) - + return self.target_path_ def add (self, ps): @@ -428,6 +428,19 @@ class PropertySet: return self.feature_map_.get(feature, []) + # FIXME: make this cached + def get_properties(self, feature): + """Returns all contained properties associated with 'feature'""" + + if not isinstance(feature, b2.build.feature.Feature): + feature = b2.build.feature.get(feature) + + result = [] + for p in self.all_: + if p.feature() == feature: + result.append(p) + return result + def __contains__(self, item): for p in self.all_set_: if p.feature().name() == "toolset": diff --git a/v2/build/targets.py b/v2/build/targets.py index f93651aaf..501647e39 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -346,9 +346,6 @@ class ProjectTarget (AbstractTarget): self.default_build_ = default_build self.build_dir_ = None - - if parent_project: - self.inherit (parent_project) # A cache of IDs self.ids_cache_ = {} @@ -372,6 +369,10 @@ class ProjectTarget (AbstractTarget): # Whether targets for all main target are already created. self.built_main_targets_ = 0 + if parent_project: + self.inherit (parent_project) + + # TODO: This is needed only by the 'make' rule. Need to find the # way to make 'make' work without this method. def project_module (self): @@ -563,7 +564,7 @@ class ProjectTarget (AbstractTarget): value = os.path.join(self.location_, value) # Now make the value absolute path value = os.path.join(os.getcwd(), value) - + self.constants_[name] = value bjam.call("set-variable", self.project_module(), name, value) @@ -571,7 +572,7 @@ class ProjectTarget (AbstractTarget): for c in parent_project.constants_: # No need to pass the type. Path constants were converted to # absolute paths already by parent. - self.add-constant(parent_project.constants_[c]) + self.add_constant(c, parent_project.constants_[c]) # Import rules from parent this_module = self.project_module() @@ -1122,7 +1123,9 @@ class BasicTarget (AbstractTarget): # usage requirements. source_targets = unique (source_targets) - result = self.construct (self.name_, source_targets, rproperties) + # FIXME: figure why this call messes up source_targets in-place + result = self.construct (self.name_, source_targets[:], rproperties) + if result: assert len(result) == 2 gur = result [0] diff --git a/v2/build/type.py b/v2/build/type.py index 62c7d7275..74d709a02 100644 --- a/v2/build/type.py +++ b/v2/build/type.py @@ -14,6 +14,7 @@ import os.path from b2.util.utility import replace_grist, os_name from b2.exceptions import * from b2.build import feature, property, scanner +from b2.util import bjam_signature __re_hyphen = re.compile ('-') @@ -53,7 +54,7 @@ def reset (): reset () - +@bjam_signature((["type"], ["suffixes", "*"], ["base_type"])) def register (type, suffixes = [], base_type = None): """ Registers a target type, possibly derived from a 'base-type'. If 'suffixes' are provided, they list all the suffixes that mean a file is of 'type'. @@ -175,6 +176,7 @@ def is_subtype (type, base): # TODO: remove this method return is_derived (type, base) +@bjam_signature((["type"], ["properties", "*"], ["suffix"])) def set_generated_target_suffix (type, properties, suffix): """ Sets a target suffix that should be used when generating target of 'type' with the specified properties. Can be called with @@ -209,6 +211,7 @@ def generated_target_suffix(type, properties): # should be used. # # Usage example: library names use the "lib" prefix on unix. +@bjam_signature((["type"], ["properties", "*"], ["suffix"])) def set_generated_target_prefix(type, properties, prefix): set_generated_target_ps(0, type, properties, prefix) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 25b672cc0..b76ee8a1e 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -65,6 +65,7 @@ import bjam import re import os.path import string +import types from b2.util import path, utility, set from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, get_value @@ -73,7 +74,8 @@ from b2.tools import common from b2.exceptions import * import b2.build.type import b2.build.property_set as property_set -import type + +import b2.build.property as property __re_starts_with_at = re.compile ('^@(.*)') @@ -158,7 +160,7 @@ class VirtualTargetRegistry: if self.files_.has_key (path): return self.files_ [path] - file_type = type.type (file) + file_type = b2.build.type.type (file) result = FileTarget (file, file_type, project, None, file_location) @@ -184,7 +186,7 @@ class VirtualTargetRegistry: # Returns all targets from 'targets' with types # equal to 'type' or derived from it. def select_by_type(self, type, targets): - return [t for t in targets if type.is_sybtype(t.type(), type)] + return [t for t in targets if b2.build.type.is_sybtype(t.type(), type)] def register_actual_name (self, actual_name, virtual_target): if self.actual_.has_key (actual_name): @@ -231,7 +233,7 @@ class VirtualTargetRegistry: """ Appends the suffix appropriate to 'type/property_set' combination to the specified name and returns the result. """ - suffix = type.generated_target_suffix (file_type, prop_set) + suffix = b2.build.type.generated_target_suffix (file_type, prop_set) if suffix: return specified_name + '.' + suffix @@ -616,7 +618,10 @@ class FileTarget (AbstractFileTarget): self.path_ = path def __str__(self): - return self.name_ + "." + self.type_ + if self.type_: + return self.name_ + "." + self.type_ + else: + return self.name_ def clone_with_different_type(self, new_type): return FileTarget(self.name_, new_type, self.project_, @@ -677,13 +682,13 @@ class FileTarget (AbstractFileTarget): """ if not self.path_: if self.action_: - p = self.action_.properties () - target_path = p.target_path () + p = self.action_.properties () + (target_path, relative_to_build_dir) = p.target_path () - if target_path [1] == True: + if relative_to_build_dir: # Indicates that the path is relative to # build dir. - target_path = os.path.join (self.project_.build_dir (), target_path [0]) + target_path = os.path.join (self.project_.build_dir (), target_path) # Store the computed path, so that it's not recomputed # any more @@ -717,6 +722,7 @@ class Action: """ def __init__ (self, manager, sources, action_name, prop_set): assert(isinstance(prop_set, property_set.PropertySet)) + assert type(sources) == types.ListType self.sources_ = sources self.action_name_ = action_name if not prop_set: @@ -815,7 +821,7 @@ class Action: # i = self.manager_.get_object (i) if i.type (): - scanner = type.get_scanner (i.type (), prop_set) + scanner = b2.build.type.get_scanner (i.type (), prop_set) r = i.actualize (scanner) result.append (r) @@ -938,7 +944,7 @@ def clone_action (action, new_project, new_action_name, new_properties): if not new_properties: new_properties = action.properties() - closed_action = action.__class__(action.sources(), new_action_name, + cloned_action = action.__class__(action.manager_, action.sources(), new_action_name, new_properties) cloned_targets = [] @@ -1018,17 +1024,25 @@ class Subvariant: either directly or indirectly, and either as sources, or as dependency properties. Targets referred with dependency property are returned a properties, not targets.""" - + # Find directly referenced targets. deps = self.build_properties().dependency() all_targets = self.sources_ + deps # Find other subvariants. r = [] - for t in all_targets: - if not t in result: - result.add(t) - r.append(t.creating_subvariant) + for e in all_targets: + if not e in result: + result.add(e) + if isinstance(e, property.Property): + t = e.value() + else: + t = e + + # FIXME: how can this be? + cs = t.creating_subvariant() + if cs: + r.append(cs) r = unique(r) for s in r: if s != self: @@ -1069,7 +1083,7 @@ class Subvariant: def compute_target_directories(self, target_type=None): result = [] for t in self.created_targets(): - if not target_type or type.is_derived(t.type(), target_type): + if not target_type or b2.build.type.is_derived(t.type(), target_type): result.append(t.path()) for d in self.other_dg_: diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index decad8501..cfe475332 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -724,3 +724,5 @@ class ArchiveGenerator (generators.Generator): ### get_manager().projects().add_rule("variant", variant) + +import stage diff --git a/v2/tools/stage.py b/v2/tools/stage.py new file mode 100644 index 000000000..82b253571 --- /dev/null +++ b/v2/tools/stage.py @@ -0,0 +1,349 @@ +# Status: ported. +# Base revision 64444. +# +# Copyright 2003 Dave Abrahams +# Copyright 2005, 2006 Rene Rivera +# Copyright 2002, 2003, 2004, 2005, 2006, 2010 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 module defines the 'install' rule, used to copy a set of targets to a +# single location. + +import b2.build.feature as feature +import b2.build.targets as targets +import b2.build.property as property +import b2.build.property_set as property_set +import b2.build.generators as generators +import b2.build.virtual_target as virtual_target + +from b2.manager import get_manager +from b2.util.sequence import unique +from b2.util import bjam_signature + +import b2.build.type + +import os.path +import re +import types + +feature.feature('install-dependencies', ['off', 'on'], ['incidental']) +feature.feature('install-type', [], ['free', 'incidental']) +feature.feature('install-source-root', [], ['free', 'path']) +feature.feature('so-version', [], ['free', 'incidental']) + +# If 'on', version symlinks for shared libraries will not be created. Affects +# Unix builds only. +feature.feature('install-no-version-symlinks', ['on'], ['optional', 'incidental']) + +class InstallTargetClass(targets.BasicTarget): + + def update_location(self, ps): + """If is not set, sets it based on the project data.""" + + loc = ps.get('location') + if not loc: + loc = os.path.join(self.project().get('location'), self.name()) + ps = ps.add_raw(["" + loc]) + + return ps + + def adjust_properties(self, target, build_ps): + a = target.action() + properties = [] + if a: + ps = a.properties() + properties = ps.all() + + # Unless true is in properties, which can happen + # only if the user has explicitly requested it, nuke all + # properties. + + if build_ps.get('hardcode-dll-paths') != ['true']: + properties = [p for p in properties if p.feature().name() != 'dll-path'] + + # If any properties were specified for installing, add + # them. + properties.extend(build_ps.get_properties('dll-path')) + + # Also copy feature from current build set, to be used + # for relinking. + properties.extend(build_ps.get_properties('linkflags')) + + # Remove the feature on original targets. + # And . If stage target has another stage target in + # sources, then we shall get virtual targets with the + # property set. + properties = [p for p in properties + if not p.feature().name() in ['tag', 'location']] + + properties.extend(build_ps.get_properties('dependency')) + + properties.extend(build_ps.get_properties('location')) + + + properties.extend(build_ps.get_properties('install-no-version-symlinks')) + + d = build_ps.get_properties('install-source-root') + + # Make the path absolute: we shall use it to compute relative paths and + # making the path absolute will help. + if d: + p = d[0] + properties.append(property.Property(p.feature(), os.path.abspath(p.value()))) + + return property_set.create(properties) + + + def construct(self, name, source_targets, ps): + + source_targets = self.targets_to_stage(source_targets, ps) + ps = self.update_location(ps) + + ename = ps.get('name') + if ename: + ename = ename[0] + if ename and len(source_targets) > 1: + get_manager().errors()("When property is used in 'install', only one source is allowed") + + result = [] + + for i in source_targets: + + staged_targets = [] + new_ps = self.adjust_properties(i, ps) + + # See if something special should be done when staging this type. It + # is indicated by the presence of a special "INSTALLED_" type. + t = i.type() + if t and b2.build.type.registered("INSTALLED_" + t): + + if ename: + get_manager().errors()("In 'install': property specified with target that requires relinking.") + else: + (r, targets) = generators.construct(self.project(), name, "INSTALLED_" + t, + new_ps, [i]) + assert isinstance(r, property_set.PropertySet) + staged_targets.extend(targets) + + else: + staged_targets.append(copy_file(self.project(), ename, i, new_ps)) + + if not staged_targets: + get_manager().errors()("Unable to generate staged version of " + i) + + result.extend(get_manager().virtual_targets().register(t) for t in staged_targets) + + return (property_set.empty(), result) + + def targets_to_stage(self, source_targets, ps): + """Given the list of source targets explicitly passed to 'stage', returns the + list of targets which must be staged.""" + + result = [] + + # Traverse the dependencies, if needed. + if ps.get('install-dependencies') == ['on']: + source_targets = self.collect_targets(source_targets) + + # Filter the target types, if needed. + included_types = ps.get('install-type') + for r in source_targets: + ty = r.type() + if ty: + # Do not stage searched libs. + if ty != "SEARCHED_LIB": + if included_types: + if self.include_type(ty, included_types): + result.append(r) + else: + result.append(r) + elif not included_types: + # Don't install typeless target if there is an explicit list of + # allowed types. + result.append(r) + + return result + + # CONSIDER: figure out why we can not use virtual-target.traverse here. + # + def collect_targets(self, targets): + + s = [t.creating_subvariant() for t in targets] + s = unique(s) + + result = set(targets) + for i in s: + i.all_referenced_targets(result) + + result2 = [] + for r in result: + if isinstance(r, property.Property): + + if r.feature().name() != 'use': + result2.append(r.value()) + else: + result2.append(r) + result2 = unique(result2) + return result2 + + # Returns true iff 'type' is subtype of some element of 'types-to-include'. + # + def include_type(self, type, types_to_include): + return any(b2.build.type.is_subtype(type, ti) for ti in types_to_include) + +# Creates a copy of target 'source'. The 'properties' object should have a +# property which specifies where the target must be placed. +# +def copy_file(project, name, source, ps): + + if not name: + name = source.name() + + relative = "" + + new_a = virtual_target.NonScanningAction([source], "common.copy", ps) + source_root = ps.get('install-source-root') + if source_root: + source_root = source_root[0] + # Get the real path of the target. We probably need to strip relative + # path from the target name at construction. + path = os.path.join(source.path(), os.path.dirname(name)) + # Make the path absolute. Otherwise, it would be hard to compute the + # relative path. The 'source-root' is already absolute, see the + # 'adjust-properties' method above. + path = os.path.abspath(path) + + relative = os.path.relpath(path, source_root) + + name = os.path.join(relative, os.path.basename(name)) + return virtual_target.FileTarget(name, source.type(), project, new_a, exact=True) + +def symlink(name, project, source, ps): + a = virtual_target.Action([source], "symlink.ln", ps) + return virtual_target.FileTarget(name, source.type(), project, a, exact=True) + +def relink_file(project, source, ps): + action = source.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. + assert len(targets) == 1 + return targets[0] + + +# Declare installed version of the EXE type. Generator for this type will cause +# relinking to the new location. +b2.build.type.register('INSTALLED_EXE', [], 'EXE') + +class InstalledExeGenerator(generators.Generator): + + def __init__(self): + generators.Generator.__init__(self, "install-exe", False, ['EXE'], ['INSTALLED_EXE']) + + def run(self, project, name, ps, source): + + need_relink = False; + + if ps.get('os') in ['NT', 'CYGWIN'] or ps.get('target-os') in ['windows', 'cygwin']: + # Never relink + pass + else: + # See if the dll-path properties are not changed during + # install. If so, copy, don't relink. + need_relink = ps.get('dll-path') != source[0].action().properties().get('dll-path') + + if need_relink: + return [relink_file(project, source, ps)] + else: + return [copy_file(project, None, source[0], ps)] + +generators.register(InstalledExeGenerator()) + + +# Installing a shared link on Unix might cause a creation of versioned symbolic +# links. +b2.build.type.register('INSTALLED_SHARED_LIB', [], 'SHARED_LIB') + +class InstalledSharedLibGenerator(generators.Generator): + + def __init__(self): + generators.Generator.__init__(self, 'install-shared-lib', False, ['SHARED_LIB'], ['INSTALLED_SHARED_LIB']) + + def run(self, project, name, ps, source): + + source = source[0] + if ps.get('os') in ['NT', 'CYGWIN'] or ps.get('target-os') in ['windows', 'cygwin']: + copied = copy_file(project, None, source, ps) + return [get_manager().virtual_targets().register(copied)] + else: + a = source.action() + if not a: + # Non-derived file, just copy. + copied = copy_file(project, source, ps) + else: + + need_relink = ps.get('dll-path') != source.action().properties().get('dll-path') + + if need_relink: + # Rpath changed, need to relink. + copied = relink_file(project, source, ps) + else: + copied = copy_file(project, None, source, ps) + + result = [get_manager().virtual_targets().register(copied)] + # If the name is in the form NNN.XXX.YYY.ZZZ, where all 'X', 'Y' and + # 'Z' are numbers, we need to create NNN.XXX and NNN.XXX.YYY + # symbolic links. + m = re.match("(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$", + copied.name()); + if m: + # Symlink without version at all is used to make + # -lsome_library work. + result.append(symlink(m.group(1), project, copied, ps)) + + # Symlinks of some libfoo.N and libfoo.N.M are used so that + # library can found at runtime, if libfoo.N.M.X has soname of + # libfoo.N. That happens when the library makes some binary + # compatibility guarantees. If not, it is possible to skip those + # symlinks. + if ps.get('install-no-version-symlinks') != ['on']: + + result.append(symlink(m.group(1) + '.' + m.group(2), project, copied, ps)) + result.append(symlink(m.group(1) + '.' + m.group(2) + '.' + m.group(3), + project, copied, ps)) + + return result + +generators.register(InstalledSharedLibGenerator()) + + +# Main target rule for 'install'. +# +@bjam_signature((["name"], ["sources", "*"], ["requirements", "*"], + ["default_build", "*"], ["usage_requirements", "*"])) +def install(name, sources, requirements, default_build, usage_requirements): + + # Unless the user has explicitly asked us to hardcode dll paths, add + # false in requirements, to override default value. + if not 'true' in requirements: + requirements.append('false') + + if any(r.startswith('') for r in requirements): + get_manager().errors()("The property is not allowed for the 'install' rule") + + from b2.manager import get_manager + t = get_manager().targets() + + project = get_manager().projects().current() + + return t.main_target_alternative( + InstallTargetClass(name, project, + t.main_target_sources(sources, name), + t.main_target_requirements(requirements, project), + t.main_target_default_build(default_build, project), + t.main_target_usage_requirements(usage_requirements, project))) + +get_manager().projects().add_rule("install", install) +get_manager().projects().add_rule("stage", install) + From 0dfa4b3a191f1078d4af3fb480046165356a6468 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 08:46:20 +0000 Subject: [PATCH 071/165] Fix the 'chain' and 'inherited_dependency' tests. [SVN r64460] --- v2/build/project.py | 2 +- v2/build/property.py | 29 +++++++++++++---------------- v2/build/property_set.py | 7 +++++++ v2/build/targets.py | 6 ++---- v2/test/chain.py | 4 ++-- v2/util/path.py | 5 +++++ 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 87f609fe2..083687544 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -750,7 +750,7 @@ class ProjectAttributes: elif attribute == "source-location": source_location = [] for path in specification: - source_location += os.path.join(self.location, path) + source_location.append(os.path.join(self.location, path)) self.__dict__["source-location"] = source_location elif attribute == "build-dir": diff --git a/v2/build/property.py b/v2/build/property.py index beea19cd4..94bc44d82 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -405,19 +405,16 @@ def take(attributes, properties): result.append(e) return result -def translate_dependencies(specification, project_id, location): +def translate_dependencies(properties, project_id, location): result = [] - for p in specification: - split = split_conditional(p) - condition = "" - if split: - condition = split[0] - p = split[1] + for p in properties: - f = get_grist(p) - v = get_value(p) - if "dependency" in feature.attributes(f): + if not p.feature().dependency(): + result.append(p) + else: + v = p.value() + print "value", v, "id", project_id m = re.match("(.*)//(.*)", v) if m: rooted = m.group(1) @@ -426,13 +423,13 @@ def translate_dependencies(specification, project_id, location): pass else: rooted = os.path.join(os.getcwd(), location, rooted[0]) - result.append(condition + f + rooted + "//" + m.group(2)) - elif os.path.isabs(m.group(v)): - result.append(condition + p) + + result.append(Property(p.feature(), rooted + "//" + m.group(2), p.condition())) + + elif os.path.isabs(v): + result.append(p) else: - result.append(condition + f + project_id + "//" + v) - else: - result.append(condition + p) + result.append(Property(p.feature(), project_id + "//" + v, p.condition())) return result diff --git a/v2/build/property_set.py b/v2/build/property_set.py index e77273510..fe91a211d 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -13,6 +13,8 @@ from b2.exceptions import * from b2.util.sequence import unique from b2.util.set import difference +from b2.manager import get_manager + def reset (): """ Clear the module state. This is mainly for testing purposes. """ @@ -68,6 +70,11 @@ def create_from_user_input(raw_properties, jamfile_module, location): properties = property.create_from_strings(raw_properties, True) properties = property.translate_paths(properties, location) properties = property.translate_indirect(properties, jamfile_module) + + project_id = get_manager().projects().attributeDefault(jamfile_module, 'id', None) + if not project_id: + project_id = os.path.abspath(location) + properties = property.translate_dependencies(properties, project_id, location) properties = property.expand_subfeatures_in_conditions(properties) return create(properties) diff --git a/v2/build/targets.py b/v2/build/targets.py index 501647e39..a5a855c95 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -776,7 +776,7 @@ class FileReference (AbstractTarget): def location (self): # Returns the location of target. Needed by 'testing.jam' if not self.file_location_: - source_location = self.project_.get ('source-location') + source_location = self.project_.get('source-location') for src_dir in source_location: location = os.path.join(src_dir, self.name()) @@ -1114,9 +1114,7 @@ class BasicTarget (AbstractTarget): self.manager_.targets().log( "Build properties: '%s'" % str(rproperties)) - extra = rproperties.get ('') - source_targets += replace_grist (extra, '') - source_targets = replace_references_by_objects (self.manager (), source_targets) + source_targets += rproperties.get('') # We might get duplicate sources, for example if # we link to two library which have the same in diff --git a/v2/test/chain.py b/v2/test/chain.py index ddc6b7308..a7cf1b831 100644 --- a/v2/test/chain.py +++ b/v2/test/chain.py @@ -19,8 +19,8 @@ t = BoostBuild.Tester() t.write("jamroot.jam", "import gcc ;") t.write("jamfile.jam", r''' -import modules ; -if [ modules.peek : NT ] +import os ; +if [ os.name ] = NT { actions create { diff --git a/v2/util/path.py b/v2/util/path.py index dc02d2497..34c4373ce 100644 --- a/v2/util/path.py +++ b/v2/util/path.py @@ -22,6 +22,9 @@ import os.path from utility import to_seq from glob import glob as builtin_glob +from b2.util import bjam_signature + +@bjam_signature((["path", "root"],)) def root (path, root): """ If 'path' is relative, it is rooted at 'root'. Otherwise, it's unchanged. """ @@ -30,6 +33,7 @@ def root (path, root): else: return os.path.join (root, path) +@bjam_signature((["native"],)) def make (native): """ Converts the native path into normalized form. """ @@ -43,6 +47,7 @@ def make_UNIX (native): return os.path.normpath (native) +@bjam_signature((["path"],)) def native (path): """ Builds a native representation of the path. """ From 4758c107f9dc739e0d9efdeac8534258ab1f0e99 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 09:44:28 +0000 Subject: [PATCH 072/165] Fix indirect conditional requirements. [SVN r64461] --- v2/build/engine.py | 11 ++--------- v2/build/targets.py | 14 +++++++++++--- v2/util/__init__.py | 15 +++++++++++++++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/v2/build/engine.py b/v2/build/engine.py index 56d5c2728..b342fe351 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -10,9 +10,9 @@ import operator import re import b2.build.property_set as property_set +import b2.util _indirect_rule = re.compile("^([^%]*)%([^%]+)$") -_extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)") class BjamAction: """Class representing bjam action defined from Python.""" @@ -42,14 +42,7 @@ class BjamNativeAction: if property_set: p = property_set.raw() - m = _extract_jamfile_and_rule.match(self.action_name) - if m: - bjam_interface.call("set-update-action-in-module", - m.group(1), m.group(2), - targets, sources, p) - else: - bjam_interface.call("set-update-action", self.action_name, - targets, sources, p) + b2.util.call_jam_function(self.action_name, targets, sources, p) action_modifiers = {"updated": 0x01, "together": 0x02, diff --git a/v2/build/targets.py b/v2/build/targets.py index a5a855c95..ce7781885 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -876,7 +876,7 @@ class BasicTarget (AbstractTarget): free_unconditional = [] other = [] for p in requirements.all(): - if p.feature().free() and not p.condition(): + if p.feature().free() and not p.condition() and p.feature().name() != 'conditional': free_unconditional.append(p) else: other.append(p) @@ -913,7 +913,6 @@ class BasicTarget (AbstractTarget): # single # # might come from project's requirements. - unconditional = feature.expand(requirements.non_conditional()) raw = context.all() @@ -949,7 +948,16 @@ class BasicTarget (AbstractTarget): # Evaluate indirect conditionals. for i in indirect: - e.extend(bjam.call(i, current)) + if callable(i): + # This is Python callable, yeah. + e.extend(bjam.call(i, current)) + else: + # Name of bjam function. Because bjam is unable to handle + # list of Property, pass list of strings. + br = b2.util.call_jam_function(i, [str(p) for p in current]) + if br: + e.extend(property.create_from_strings(br)) + if e == added_requirements: # If we got the same result, we've found final properties. diff --git a/v2/util/__init__.py b/v2/util/__init__.py index 5cee29f55..89da84909 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -1,4 +1,7 @@ +import bjam +import re + # Decorator the specifies bjam-side prototype for a Python function def bjam_signature(s): @@ -27,3 +30,15 @@ def unquote(s): return s[1:-1] else: return s + +_extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)") + +def call_jam_function(name, *args): + + m = _extract_jamfile_and_rule.match(name) + if m: + args = ("set-update-action-in-module", m.group(1), m.group(2)) + args + else: + args = ("set-update-action", name) + args + + return bjam.call(*args) From 9d74dfc4dc4c8eede30d4ea6b0db05a97e1d44fb Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 10:04:07 +0000 Subject: [PATCH 073/165] Fix process of dependency properties [SVN r64462] --- v2/build/property.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/v2/build/property.py b/v2/build/property.py index 94bc44d82..d98eb8a41 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -414,7 +414,6 @@ def translate_dependencies(properties, project_id, location): result.append(p) else: v = p.value() - print "value", v, "id", project_id m = re.match("(.*)//(.*)", v) if m: rooted = m.group(1) @@ -422,7 +421,7 @@ def translate_dependencies(properties, project_id, location): # Either project id or absolute Linux path, do nothing. pass else: - rooted = os.path.join(os.getcwd(), location, rooted[0]) + rooted = os.path.join(os.getcwd(), location, rooted) result.append(Property(p.feature(), rooted + "//" + m.group(2), p.condition())) From 8ce2090f996ba6bc95d141ca9b8988232f03505d Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 10:14:15 +0000 Subject: [PATCH 074/165] Fix 'glob-in-tree'. [SVN r64463] --- v2/build/project.py | 2 +- v2/util/path.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 083687544..c0cdb8649 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -978,7 +978,7 @@ attribute is allowed only for top-level 'project' invocations""") bad = 1 if bad: - self.registry.manager().errors()( + self.registry.manager.errors()( "The patterns to 'glob-tree' may not include directory") return self.registry.glob_internal(self.registry.current(), wildcards, excludes, "glob_tree") diff --git a/v2/util/path.py b/v2/util/path.py index 34c4373ce..222b96bfe 100644 --- a/v2/util/path.py +++ b/v2/util/path.py @@ -848,7 +848,7 @@ def glob_tree(roots, patterns, exclude_patterns=None): exclude_patterns = [] result = glob(roots, patterns, exclude_patterns) - subdirs = [s for s in result if s != "." and s != ".." and os.path.isdir(s)] + subdirs = [s for s in glob(roots, ["*"]) if s != "." and s != ".." and os.path.isdir(s)] if subdirs: result.extend(glob_tree(subdirs, patterns, exclude_patterns)) From 0603e8f0c7e18d7e55667971c6dc01fb69512d00 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 10:34:02 +0000 Subject: [PATCH 075/165] Improve reporting of 'duplicate virtual target'. [SVN r64464] --- v2/build/virtual_target.py | 26 +++++++++++++++----------- v2/build_system.py | 5 ++++- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index b76ee8a1e..915ab03e8 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -77,6 +77,8 @@ import b2.build.property_set as property_set import b2.build.property as property +from b2.manager import get_manager + __re_starts_with_at = re.compile ('^@(.*)') class VirtualTargetRegistry: @@ -213,17 +215,19 @@ class VirtualTargetRegistry: if not properties_added: properties_added = "none" # FIXME: Revive printing of real location. - raise BaseException ("Duplicate name of actual target: '%s'\n" - "previous virtual target '%s'\n" - "created from '%s'\n" - "another virtual target '%s'\n" - "created from '%s'\n" - "added properties: '%s'\n" - "removed properties: '%s'\n" % (actual_name, - self.actual_ [actual_name], "loc", #cmt1.location (), - virtual_target, - "loc", #cmt2.location (), - properties_added, properties_removed)) + get_manager().errors()( + "Duplicate name of actual target: '%s'\n" + "previous virtual target '%s'\n" + "created from '%s'\n" + "another virtual target '%s'\n" + "created from '%s'\n" + "added properties: '%s'\n" + "removed properties: '%s'\n" + % (actual_name, + self.actual_ [actual_name], "loc", #cmt1.location (), + virtual_target, + "loc", #cmt2.location (), + properties_added, properties_removed)) else: self.actual_ [actual_name] = virtual_target diff --git a/v2/build_system.py b/v2/build_system.py index 93ecd651a..3956481a5 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -441,7 +441,10 @@ def main(): stats.sort_stats('time', 'calls') stats.print_callers(20) else: - return main_real() + try: + return main_real() + except ExceptionWithUserContext, e: + e.report() def main_real(): From 827d51a1fec74621d18ab55a40c85ca18f9cb6b8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 11:14:06 +0000 Subject: [PATCH 076/165] Port processing of relative paths in sources. [SVN r64465] --- v2/build/generators.py | 26 +++++++++++++++++++++++--- v2/build/project.py | 18 ++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index d2106033e..4dea2afda 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -349,6 +349,21 @@ class Generator: return result + def determine_target_name(self, fullname): + # Determine target name from fullname (maybe including path components) + # Place optional prefix and postfix around basename + + dir = os.path.dirname(fullname) + name = os.path.basename(fullname) + + if dir and not ".." in dir and not os.path.isabs(dir): + # Relative path is always relative to the source + # directory. Retain it, so that users can have files + # with the same in two different subdirectories. + name = dir + "/" + name + + return name + def determine_output_name(self, sources): """Determine the name of the produced target from the names of the sources.""" @@ -371,8 +386,8 @@ class Generator: "%s: source targets have different names: cannot determine target name" % (self.id_)) - # Names of sources might include directory. We should strip it. - return os.path.basename(name) + # Names of sources might include directory. We should strip it. + return self.determine_target_name(sources[0].name()) def generated_targets (self, sources, prop_set, project, name): @@ -409,7 +424,12 @@ class Generator: pre = self.name_prefix_ post = self.name_postfix_ for t in self.target_types_: - generated_name = pre[0] + name + post[0] + 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:] post = post[1:] diff --git a/v2/build/project.py b/v2/build/project.py index c0cdb8649..9d2f3acc0 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -565,12 +565,12 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) return self.project_rules_ def glob_internal(self, project, wildcards, excludes, rule_name): - location = project.get("source-location") + location = project.get("source-location")[0] result = [] callable = b2.util.path.__dict__[rule_name] - paths = callable(location, wildcards, excludes) + paths = callable([location], wildcards, excludes) has_dir = 0 for w in wildcards: if os.path.dirname(w): @@ -578,11 +578,21 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) break if has_dir or rule_name != "glob": + result = [] # The paths we've found are relative to current directory, # but the names specified in sources list are assumed to # be relative to source directory of the corresponding - # prject. So, just make the name absolute. - result = [os.path.join(os.getcwd(), p) for p in paths] + # prject. Either translate them or make absolute. + + for p in paths: + rel = os.path.relpath(p, location) + # If the path is below source location, use relative path. + if not ".." in rel: + result.append(rel) + else: + # Otherwise, use full path just to avoid any ambiguities. + result.append(os.path.abspath(p)) + else: # There were not directory in wildcard, so the files are all # in the source directory of the project. Just drop the From 805cfc589f73d1df8fb4a5e2b6620d475a604647 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 20:57:40 +0000 Subject: [PATCH 077/165] Adjust profiling code [SVN r64487] --- v2/build_system.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/v2/build_system.py b/v2/build_system.py index 3956481a5..9d2f05f26 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -433,13 +433,14 @@ def main(): # FIXME: document this option. if "--profiling" in sys.argv: import cProfile + r = cProfile.runctx('main_real()', globals(), locals(), "stones.prof") + import pstats - return cProfile.runctx('main_real()', globals(), locals(), "stones.prof") - stats = pstats.Stats("stones.prof") stats.strip_dirs() stats.sort_stats('time', 'calls') stats.print_callers(20) + return r else: try: return main_real() From facac5e87cd4fa21a2d4d1f820623cba9a7c79fd Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 30 Jul 2010 20:59:08 +0000 Subject: [PATCH 078/165] Remove unused method [SVN r64488] --- v2/build/generators.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index 4dea2afda..b1e62d2a9 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -105,14 +105,6 @@ def dout(message): if debug(): print __indent + message -def normalize_target_list (targets): - """ Takes a vector of 'virtual-target' instances and makes a normalized - representation, which is the same for given set of targets, - regardless of their order. - """ - return (targets[0], targets[1].sort ()) - - class Generator: """ Creates a generator. manager: the build manager. From b5d7178237d110314a5203ff489fd22b5bec81fe Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 31 Jul 2010 08:02:35 +0000 Subject: [PATCH 079/165] Complete porting of build/project.jam [SVN r64491] --- v2/build/project.py | 75 +++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 9d2f3acc0..20c11c506 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -1,5 +1,5 @@ -# Status: being ported by Vladimir Prus -# Base revision: 42507 +# Status: ported. +# Base revision: 64488 # Copyright 2002, 2003 Dave Abrahams # Copyright 2002, 2005, 2006 Rene Rivera @@ -51,6 +51,7 @@ import os import string import imp import traceback +import b2.util.option as option class ProjectRegistry: @@ -133,7 +134,7 @@ class ProjectRegistry: # If Jamfile is already loaded, don't try again. if not mname in self.jamfile_modules: - self.load_jamfile(jamfile_location) + self.load_jamfile(jamfile_location, mname) # We want to make sure that child project are loaded only # after parent projects. In particular, because parent projects @@ -285,7 +286,7 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" if jamfile_glob: return jamfile_glob[0] - def load_jamfile(self, dir): + def load_jamfile(self, dir, jamfile_module): """Load a Jamfile at the given directory. Returns nothing. Will attempt to load the file as indicated by the JAMFILE patterns. Effect of calling this rule twice with the same 'dir' is underfined.""" @@ -296,13 +297,16 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" if not jamfile_to_load: jamfile_to_load = self.find_jamfile(dir) else: + if len(jamfile_to_load) > 1: + get_manager().errors()("Multiple Jamfiles found at '%s'\n" +\ + "Filenames are: %s" + % (dir, [os.path.basename(j) for j in jamfile_to_load])) + is_jamroot = True jamfile_to_load = jamfile_to_load[0] # The module of the jamfile. - dir = os.path.realpath(os.path.dirname(jamfile_to_load)) - - jamfile_module = self.module_name (dir) + dir = os.path.realpath(os.path.dirname(jamfile_to_load)) # Initialize the jamfile module before loading. # @@ -401,8 +405,13 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) if location: attributes.set("source-location", [location], exact=1) - else: - attributes.set("source-location", "", exact=1) + elif not 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. + module = sys.modules[module_name] + attributes.set("source-location", module.__path__, exact=1) attributes.set("requirements", property_set.empty(), exact=True) attributes.set("usage-requirements", property_set.empty(), exact=True) @@ -416,11 +425,15 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) jamroot = False parent_module = None; - if module_name == "site-config": + if module_name == "test-config": # No parent pass + elif module_name == "site-config": + parent_module = "test-config" elif module_name == "user-config": parent_module = "site-config" + elif module_name == "project-config": + parent_module = "user-config" elif location and not self.is_jamroot(basename): # We search for parent/project-root only if jamfile was specified # --- i.e @@ -430,7 +443,12 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # It's either jamroot, or standalone project. # If it's jamroot, inherit from user-config. if location: - parent_module = "user-config" ; + # If project-config module exist, inherit from it. + if self.module2attributes.has_key("project-config"): + parent_module = "project-config" + else: + parent_module = "user-config" ; + jamroot = True ; if parent_module: @@ -550,7 +568,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # that id is not equal to the 'id' parameter. if self.id2module.has_key(id) and self.id2module[id] != project_module: self.manager.errors()( -"""Attempt to redeclare already existing project id '%s'""" % id) +"""Attempt to redeclare already existing project id '%s' at location '%s'""" % (id, location)) self.id2module[id] = project_module self.current_module = saved_project @@ -765,8 +783,15 @@ class ProjectAttributes: elif attribute == "build-dir": self.__dict__["build-dir"] = os.path.join(self.location, specification[0]) - - elif not attribute in ["id", "default-build", "location", + + elif attribute == "id": + id = specification[0] + if id[0] != '/': + id = "/" + id + self.manager.projects().register_id(id, self.project_module) + self.__dict__["id"] = id + + elif not attribute in ["default-build", "location", "source-location", "parent", "projects-to-build", "project-root"]: self.manager.errors()( @@ -898,11 +923,7 @@ class ProjectRules: args = args[1:] if id: - if id[0] != '/': - id = '/' + id - self.registry.register_id (id, jamfile_module) - - attributes.set('id', id) + attributes.set('id', [id]) explicit_build_dir = None for a in args: @@ -920,6 +941,10 @@ class ProjectRules: # If we try to set build dir for user-config, we'll then # try to inherit it, with either weird, or wrong consequences. if location and location == attributes.get("project-root"): + # Re-read the project id, since it might have been changed in + # the project's attributes. + id = attributes.get('id') + # This is Jamroot. if id: if explicit_build_dir and os.path.isabs(explicit_build_dir): @@ -972,6 +997,11 @@ attribute is allowed only for top-level 'project' invocations""") for n in target_names: t.mark_target_as_explicit(n) + def always(self, target_names): + p = self.registry.current() + for n in target_names: + p.mark_target_as_always(n) + def glob(self, wildcards, excludes=None): return self.registry.glob_internal(self.registry.current(), wildcards, excludes, "glob") @@ -1062,3 +1092,10 @@ attribute is allowed only for top-level 'project' invocations""") return self.reverse[jamfile_module].get(name_in_jamfile_modue, None) return None + + def option(self, name, value): + name = name[0] + if not name in ["site-config", "user-config", "project-config"]: + get_manager().errors()("The 'option' rule may be used only in site-config or user-config") + + option.set(name, value[0]) From 4d60eb88f679ed5ec384f79dcb6e97f6eeaf0646 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 31 Jul 2010 11:40:34 +0000 Subject: [PATCH 080/165] Don't bark on conditionals in usage requirements. [SVN r64496] --- v2/build/project.py | 11 ++++++----- v2/build/property.py | 6 +++--- v2/build/property_set.py | 18 ++++-------------- v2/build/targets.py | 2 +- 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 20c11c506..0cadc397c 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -758,15 +758,16 @@ class ProjectAttributes: non_free = property.remove("free", unconditional) if non_free: - pass - # FIXME: - #errors.error "usage-requirements" $(specification) "have non-free properties" $(non-free) ; + get_manager().errors()("usage-requirements %s have non-free properties %s" \ + % (specification, non_free)) - t = property.translate_paths(property.create_from_strings(specification), self.location) + t = property.translate_paths( + property.create_from_strings(specification, allow_condition=True), + self.location) existing = self.__dict__.get("usage-requirements") if existing: - new = property_set.create(existing.raw() + t) + new = property_set.create(existing.all() + t) else: new = property_set.create(t) self.__dict__["usage-requirements"] = new diff --git a/v2/build/property.py b/v2/build/property.py index d98eb8a41..633301d60 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -60,7 +60,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): condition = [] import types @@ -98,9 +98,9 @@ def create_from_string(s, allow_condition = False): return Property(f, value, condition) -def create_from_strings(string_list, validate=False): +def create_from_strings(string_list, allow_condition=False): - return [create_from_string(s, validate) for s in string_list] + return [create_from_string(s, allow_condition) for s in string_list] def reset (): """ Clear the module state. This is mainly for testing purposes. diff --git a/v2/build/property_set.py b/v2/build/property_set.py index fe91a211d..589382423 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -154,7 +154,6 @@ class PropertySet: self.incidental_ = [] self.free_ = [] self.base_ = [] - self.base_raw_ = [] self.dependency_ = [] self.non_dependency_ = [] self.conditional_ = [] @@ -199,18 +198,7 @@ class PropertySet: raise BaseException ("Invalid property: '%s'" % p) att = feature.attributes (get_grist (p)) - - # A feature can be both incidental and free, - # in which case we add it to incidental. - if 'incidental' in att: - pass -# self.incidental_.append (p) - elif 'free' in att: - # self.free_.append (p) - pass - else: - self.base_raw_.append (p) - + if 'propagated' in att: self.propagated_.append (p) @@ -219,6 +207,8 @@ class PropertySet: for p in properties: + # A feature can be both incidental and free, + # in which case we add it to incidental. if p.feature().incidental(): self.incidental_.append(p) elif p.feature().free(): @@ -251,7 +241,7 @@ class PropertySet: def base (self): """ Returns properties that are neither incidental nor free. """ - return self.base_raw_ + return self.base_ def free (self): """ Returns free properties which are not dependency properties. diff --git a/v2/build/targets.py b/v2/build/targets.py index ce7781885..6be8ffec3 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -1019,7 +1019,7 @@ class BasicTarget (AbstractTarget): if debug: print " next alternative: required properties:", str(condition) - if b2.util.set.contains (condition, property_set.raw ()): + if b2.util.set.contains (condition, property_set.all()): if debug: print " matched" From a7a600ec4018ec2692c68d7ad025d998081a453a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 10:07:43 +0000 Subject: [PATCH 081/165] Update build/feature.py. [SVN r64536] --- v2/build/feature.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/v2/build/feature.py b/v2/build/feature.py index 3f09d9da5..40a624d02 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -1,6 +1,5 @@ -# Status: mostly ported. -# TODO: carry over tests. -# Base revision: 56043 +# Status: ported, except for unit tests. +# Base revision: 64488 # # Copyright 2001, 2002, 2003 Dave Abrahams # Copyright 2002, 2006 Rene Rivera @@ -8,10 +7,6 @@ # 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: stop using grists to identify the name of features? -# create a class for Features and Properties? -# represent conditions using object trees, composite pattern? - import re from b2.util import utility, bjam_signature @@ -438,7 +433,8 @@ def validate_value_string (f, value_string): values = [value_string] if f.subfeatures(): - if not value_string in f.subfeatures(): + if not value_string in f.values() and \ + not value_string in f.subfeatures(): values = value_string.split('-') # An empty value is allowed for optional features From 4e3c57b819f9c0c1b93bd25dc4ac18508bbd1a5f Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 11:38:54 +0000 Subject: [PATCH 082/165] Complete porting of build/targets.jam [SVN r64537] --- v2/build/generators.py | 23 +++++- v2/build/targets.py | 165 +++++++++++++++++++++++++++-------------- v2/util/sequence.py | 24 +++--- 3 files changed, 139 insertions(+), 73 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index b1e62d2a9..6b6d36d0f 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -853,7 +853,7 @@ def find_viable_generators_aux (target_type, prop_set): m = g.match_rank(prop_set) if m: dout(" is viable") - viable_generators.append(g) + viable_generators.append(g) return viable_generators @@ -873,6 +873,8 @@ def find_viable_generators (target_type, prop_set): # TODO: is this really used? if not g in __active_generators: viable_generators.append (g) + else: + dout(" generator %s is active, discarning" % g.id()) # Generators which override 'all'. all_overrides = [] @@ -941,7 +943,7 @@ def __construct_really (project, name, target_type, prop_set, sources): return result; -def construct (project, name, target_type, prop_set, sources): +def construct (project, name, target_type, prop_set, sources, top_level=False): """ Attempts to create target of 'target-type' with 'properties' from 'sources'. The 'sources' are treated as a collection of *possible* ingridients -- i.e. it is not required to consume @@ -951,9 +953,19 @@ def construct (project, name, target_type, prop_set, sources): Returns a list of target. When this invocation is first instance of 'construct' in stack, returns only targets of requested 'target-type', otherwise, returns also unused sources and additionally generated - targets. + targets. + + If 'top-level' is set, does not suppress generators that are already + used in the stack. This may be useful in cases where a generator + has to build a metatargets -- for example a target corresponding to + built tool. """ - # TODO: Why is global needed here? + + global __active_generators + if top_level: + saved_active = __active_generators + __active_generators = [] + global __construct_stack if __construct_stack: __ensure_type (sources) @@ -976,5 +988,8 @@ def construct (project, name, target_type, prop_set, sources): __construct_stack = __construct_stack [1:] + if top_level: + __active_generators = saved_active + return result diff --git a/v2/build/targets.py b/v2/build/targets.py index 6be8ffec3..4cc3f0a98 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -1,7 +1,5 @@ -# Status: being ported by Vladimir Prus -# Still to do: call toolset.requirements when those are ported. -# Remember the location of target. -# Base revision: 40480 +# Status: ported. +# Base revision: 64488 # Copyright Vladimir Prus 2002-2007. # Copyright Rene Rivera 2006. @@ -104,6 +102,8 @@ class TargetRegistry: self.debug_building_ = "--debug-building" in bjam.variable("ARGV") + self.targets_ = [] + def main_target_alternative (self, target): """ Registers the specified target as a main target alternatives. Returns 'target'. @@ -232,6 +232,16 @@ class TargetRegistry: if self.debug_building_: print self.indent_ + message + def push_target(self, target): + self.targets_.append(target) + + def pop_target(self): + self.targets_ = self.targets_[:-1] + + def current(self): + return self.targets_[0] + + class GenerateResult: def __init__ (self, ur=None, targets=None): @@ -363,6 +373,9 @@ class ProjectTarget (AbstractTarget): # Targets marked as explicit. self.explicit_targets_ = set() + # Targets marked as always + self.always_targets_ = set() + # The constants defined for this project. self.constants_ = {} @@ -423,7 +436,7 @@ class ProjectTarget (AbstractTarget): # Collect all projects referenced via "projects-to-build" attribute. self_location = self.get ('location') for pn in self.get ('projects-to-build'): - result.append (self.find(pn)) + result.append (self.find(pn + "/")) return result @@ -434,6 +447,9 @@ class ProjectTarget (AbstractTarget): # Record the name of the target, not instance, since this # rule is called before main target instaces are created. self.explicit_targets_.add(target_name) + + def mark_target_as_always(self, target_name): + self.always_targets_.add(target_name) def add_alternative (self, target_instance): """ Add new target alternative. @@ -548,6 +564,9 @@ class ProjectTarget (AbstractTarget): if not self.main_target_.has_key (name): t = MainTarget (name, self.project_) self.main_target_ [name] = t + + if name in self.always_targets_: + a.always() self.main_target_ [name].add_alternative (a) @@ -561,7 +580,16 @@ class ProjectTarget (AbstractTarget): """ if path: - value = os.path.join(self.location_, value) + l = self.location_ + if not l: + # Project corresponding to config files do not have + # 'location' attribute, but do have source location. + # It might be more reasonable to make every project have + # a location and use some other approach to prevent buildable + # targets in config files, but that's for later. + l = get('source-location') + + value = os.path.join(l, value) # Now make the value absolute path value = os.path.join(os.getcwd(), value) @@ -660,46 +688,7 @@ class MainTarget (AbstractTarget): return best def apply_default_build (self, property_set): - # 1. First, see what properties from default_build - # are already present in property_set. - - specified_features = set(p.feature() for p in property_set.all()) - - defaults_to_apply = [] - for d in self.default_build_.all(): - if not d.feature() in specified_features: - defaults_to_apply.append(d) - - # 2. If there's any defaults to be applied, form the new - # build request. Pass it throw 'expand-no-defaults', since - # default_build might contain "release debug", which will - # result in two property_sets. - result = [] - if defaults_to_apply: - - # We have to compress subproperties here to prevent - # property lists like: - # - # msvc 7.1 multi - # - # from being expanded into: - # - # 7.1/multi - # msvc/7.1/multi - # - # due to cross-product property combination. That may - # be an indication that - # build_request.expand-no-defaults is the wrong rule - # to use here. - compressed = feature.compress_subproperties(property_set.all()) - - result = build_request.expand_no_defaults( - b2.build.property_set.create([p]) for p in (compressed + defaults_to_apply)) - - else: - result.append (property_set) - - return result + return apply_default_build(property_set, self.default_build_) def generate (self, ps): """ Select an alternative for this main target, by finding all alternatives @@ -821,11 +810,16 @@ class BasicTarget (AbstractTarget): self.request_cache = {} self.user_context_ = self.manager_.errors().capture_user_context() + + self.always_ = False + + def always(self): + self.always_ = True def sources (self): """ Returns the list of AbstractTargets which are used as sources. The extra properties specified for sources are not represented. - The only used of this rule at the moment is the '--dump-test' + The only used of this rule at the moment is the '--dump-tests' feature of the test system. """ if self.source_targets_ == None: @@ -1084,6 +1078,8 @@ class BasicTarget (AbstractTarget): "Command line free features: '%s'" % str (cf.raw ())) self.manager().targets().log( "Target requirements: %s'" % str (self.requirements().raw ())) + + self.manager().targets().push_target(self) if not self.generated_.has_key(ps): @@ -1127,7 +1123,10 @@ class BasicTarget (AbstractTarget): # We might get duplicate sources, for example if # we link to two library which have the same in # usage requirements. - source_targets = unique (source_targets) + # Use stable sort, since for some targets the order is + # important. E.g. RUN_PY target need python source to come + # first. + source_targets = unique(source_targets, stable=True) # FIXME: figure why this call messes up source_targets in-place result = self.construct (self.name_, source_targets[:], rproperties) @@ -1137,6 +1136,10 @@ class BasicTarget (AbstractTarget): gur = result [0] result = result [1] + if self.always_: + for t in result: + t.always() + s = self.create_subvariant ( result, self.manager().virtual_targets().recent_targets(), ps, @@ -1155,17 +1158,25 @@ class BasicTarget (AbstractTarget): else: self.generated_[ps] = GenerateResult (property_set.empty(), []) else: - self.manager().targets().log( - "Skipping build: no in common properties") + # If we just see no, we cannot produce any reasonable + # diagnostics. The code that adds this property is expected + # to explain why a target is not built, for example using + # the configure.log-component-configuration function. - # We're here either because there's error computing - # properties, or there's no in properties. - # In the latter case we don't want any diagnostic. - # In the former case, we need diagnostics. TODOo - self.generated_[ps] = GenerateResult (rproperties, []) + # If this target fails to build, add no to properties + # to cause any parent target to fail to build. Except that it + # - does not work now, since we check for no only in + # common properties, but not in properties that came from + # dependencies + # - it's not clear if that's a good idea anyway. The alias + # target, for example, should not fail to build if a dependency + # fails. + self.generated_[ps] = GenerateResult( + property_set.create(["no"]), []) else: self.manager().targets().log ("Already built") + self.manager().targets().pop_target() self.manager().targets().decrease_indent() return self.generated_[ps] @@ -1273,7 +1284,7 @@ class TypedTarget (BasicTarget): r = generators.construct (self.project_, name, self.type_, prop_set.add_raw(['' + self.type_]), - source_targets) + source_targets, True) if not r: print "warning: Unable to construct '%s'" % self.full_name () @@ -1290,6 +1301,48 @@ class TypedTarget (BasicTarget): return r +def apply_default_build(property_set, default_build): + # 1. First, see what properties from default_build + # are already present in property_set. + + specified_features = set(p.feature() for p in property_set.all()) + + defaults_to_apply = [] + for d in default_build.all(): + if not d.feature() in specified_features: + defaults_to_apply.append(d) + + # 2. If there's any defaults to be applied, form the new + # build request. Pass it throw 'expand-no-defaults', since + # default_build might contain "release debug", which will + # result in two property_sets. + result = [] + if defaults_to_apply: + + # We have to compress subproperties here to prevent + # property lists like: + # + # msvc 7.1 multi + # + # from being expanded into: + # + # 7.1/multi + # msvc/7.1/multi + # + # due to cross-product property combination. That may + # be an indication that + # build_request.expand-no-defaults is the wrong rule + # to use here. + compressed = feature.compress_subproperties(property_set.all()) + + result = build_request.expand_no_defaults( + b2.build.property_set.create([p]) for p in (compressed + defaults_to_apply)) + + else: + result.append (property_set) + + return result + def create_typed_metatarget(name, type, sources, requirements, default_build, usage_requirements): diff --git a/v2/util/sequence.py b/v2/util/sequence.py index a0160107d..1d32efd2e 100644 --- a/v2/util/sequence.py +++ b/v2/util/sequence.py @@ -5,19 +5,17 @@ import operator -def unique (values): - # TODO: is this the most efficient way? - # consider using a set from Python 2.4. - return list(set(values)) -# cache = {} -# result = [] -# for v in values: -# if not cache.has_key(v): -# cache[v] = None -# result.append(v) -# return result - - +def unique (values, stable=False): + if stable: + s = set() + r = [] + for v in values: + if not v in s: + r.append(v) + s.add(v) + return r + else: + return list(set(values)) def max_element (elements, ordered = None): """ Returns the maximum number in 'elements'. Uses 'ordered' for comparisons, From 680a1297e8c38b937c8298175dbac01fe06a4b6c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 11:47:59 +0000 Subject: [PATCH 083/165] Update base revision comment [SVN r64538] --- v2/build/virtual_target.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 915ab03e8..a7060123f 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -1,5 +1,5 @@ # Status: ported. -# Base revision: 64427. +# Base revision: 64488. # # Copyright (C) Vladimir Prus 2002. Permission to copy, use, modify, sell and # distribute this software is granted provided this copyright notice appears in From eb262a3d350bbb1c1c5cb2ea52c80523abd7505c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 14:15:50 +0000 Subject: [PATCH 084/165] Partially upgrade build/generators.py [SVN r64539] --- v2/build/generators.py | 134 ++++++++++++++++++++++++++++----- v2/build/type.py | 13 ++++ v2/test/generator_selection.py | 22 ++++++ v2/util/logger.py | 2 +- 4 files changed, 150 insertions(+), 21 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index 6b6d36d0f..39696def3 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -1,5 +1,5 @@ # Status: being ported by Vladimir Prus -# Base revision: 41557 +# Base revision: 48649 # TODO: replace the logging with dout # Copyright Vladimir Prus 2002. @@ -59,6 +59,7 @@ from b2.util import set from b2.util.sequence import unique import b2.util.sequence as sequence from b2.manager import get_manager +import b2.build.type def reset (): """ Clear the module state. This is mainly for testing purposes. @@ -66,6 +67,7 @@ def reset (): global __generators, __type_to_generators, __generators_for_toolset, __construct_stack global __overrides, __active_generators global __viable_generators_cache, __viable_source_types_cache + global __vstg_cached_generators, __vst_cached_types __generators = {} __type_to_generators = {} @@ -78,6 +80,9 @@ def reset (): __viable_source_types_cache = {} __active_generators = [] + __vstg_cached_generators = [] + __vst_cached_types = [] + reset () _re_separate_types_prefix_and_postfix = re.compile ('([^\\(]*)(\\((.*)%(.*)\\))?') @@ -101,6 +106,54 @@ def decrease_indent(): global __indent __indent = __indent[0:-4] + +# Updated cached viable source target type information as needed after a new +# derived target type gets added. This is needed because if a target type is a +# viable source target type for some generator then all of the target type's +# derived target types are automatically viable as source target types for the +# same generator. Does nothing if a non-derived target type is passed to it. +# +def update_cached_information_with_a_new_type(type): + + base_type = b2.build.type.base(type) + + if base_type: + for g in __vstg_cached_generators: + if base_type in __viable_source_types_cache.get(g, []): + __viable_source_types_cache[g].append(type) + + for t in __vst_cached_types: + if base_type in __viable_source_types_cache.get(t, []): + __viable_source_types_cache[t].append(type) + +# Clears cached viable source target type information except for target types +# and generators with all source types listed as viable. Should be called when +# something invalidates those cached values by possibly causing some new source +# types to become viable. +# +def invalidate_extendable_viable_source_target_type_cache(): + + global __vstg_cached_generators + generators_with_cached_source_types = __vstg_cached_generators + __vstg_cached_generators = [] + + for g in generators_with_cached_source_types: + if __viable_source_types_cache.has_key(g): + if __viable_source_types_cache[g] == ["*"]: + __vstg_cached_generators.append(g) + else: + del __viable_source_types_cache[g] + + global __vst_cached_types + types_with_cached_sources_types = __vst_cached_types + __vst_cached_types = [] + for t in types_with_cached_sources_types: + if __viable_source_types_cache.has_key(t): + if __viable_source_types_cache[t] == ["*"]: + __vst_cached_types.append(t) + else: + del __viable_source_types_cache[t] + def dout(message): if debug(): print __indent + message @@ -589,6 +642,24 @@ def register (g): __generators_for_toolset.setdefault(base, []).append(g) + # After adding a new generator that can construct new target types, we need + # to clear the related cached viable source target type information for + # constructing a specific target type or using a specific generator. Cached + # viable source target type lists affected by this are those containing any + # of the target types constructed by the new generator or any of their base + # target types. + # + # A more advanced alternative to clearing that cached viable source target + # type information would be to expand it with additional source types or + # even better - mark it as needing to be expanded on next use. + # + # For now we just clear all the cached viable source target type information + # that does not simply state 'all types' and may implement a more detailed + # algorithm later on if it becomes needed. + + invalidate_extendable_viable_source_target_type_cache() + + def register_standard (id, source_types, target_types, requirements = []): """ Creates new instance of the 'generator' class and registers it. Returns the creates instance. @@ -632,11 +703,19 @@ def __viable_source_types_real (target_type): of calling itself recusrively on source types. """ generators = [] - - t = type.all_bases (target_type) + + # 't0' is the initial list of target types we need to process to get a list + # of their viable source target types. New target types will not be added to + # this list. + t0 = type.all_bases (target_type) + + + # 't' is the list of target types which have not yet been processed to get a + # list of their viable source target types. This list will get expanded as + # we locate more target types to process. + t = t0 result = [] - # 't' is the list of types which are not yet processed while t: # Find all generators for current type. # Unlike 'find_viable_generators' we don't care about prop_set. @@ -658,19 +737,29 @@ def __viable_source_types_real (target_type): all = type.all_derived (source_type) for n in all: if not n in result: - t.append (n) + + # Here there is no point in adding target types to + # the list of types to process in case they are or + # have already been on that list. We optimize this + # check by realizing that we only need to avoid the + # original target type's base types. Other target + # types that are or have been on the list of target + # types to process have been added to the 'result' + # list as well and have thus already been eliminated + # by the previous if. + if not n in t0: + t.append (n) result.append (n) - - result = unique (result) - + return result def viable_source_types (target_type): """ Helper rule, caches the result of '__viable_source_types_real'. """ - if not __viable_source_types_cache.has_key (target_type): - __viable_source_types_cache [target_type] = __viable_source_types_real (target_type) + if not __viable_source_types_cache.has_key(target_type): + __vst_cached_types.append(target_type) + __viable_source_types_cache [target_type] = __viable_source_types_real (target_type) return __viable_source_types_cache [target_type] def viable_source_types_for_generator_real (generator): @@ -691,20 +780,22 @@ def viable_source_types_for_generator_real (generator): else: result = [] for s in source_types: - result += type.all_derived (s) + viable_source_types (s) - result = unique (result) - if "*" in result: - result = ["*"] - return result + viable_sources = viable_source_types(s) + if viable_sources == "*": + result = ["*"] + break + else: + result.extend(type.all_derived(s) + viable_sources) + return unique(result) def viable_source_types_for_generator (generator): """ Caches the result of 'viable_source_types_for_generator'. """ - key = str (generator) - if not __viable_source_types_cache.has_key (key): - __viable_source_types_cache [key] = viable_source_types_for_generator_real (generator) + if not __viable_source_types_cache.has_key(generator): + __vstg_cached_generators.append(generator) + __viable_source_types_cache[generator] = viable_source_types_for_generator_real (generator) - return __viable_source_types_cache [key] + return __viable_source_types_cache[generator] def try_one_generator_really (project, name, generator, target_type, properties, sources): """ Returns usage requirements + list of created targets. @@ -861,6 +952,8 @@ def find_viable_generators (target_type, prop_set): key = target_type + '.' + str (prop_set) l = __viable_generators_cache.get (key, None) + if not l: + l = [] if not l: l = find_viable_generators_aux (target_type, prop_set) @@ -899,6 +992,7 @@ def find_viable_generators (target_type, prop_set): for g in viable_generators: if not g.id () in overriden_ids: result.append (g) + return result @@ -909,7 +1003,7 @@ def __construct_really (project, name, target_type, prop_set, sources): viable_generators = find_viable_generators (target_type, prop_set) result = [] - + project.manager ().logger ().log (__name__, "*** %d viable generators" % len (viable_generators)) generators_that_succeeded = [] diff --git a/v2/build/type.py b/v2/build/type.py index 74d709a02..b04547458 100644 --- a/v2/build/type.py +++ b/v2/build/type.py @@ -16,6 +16,7 @@ from b2.exceptions import * from b2.build import feature, property, scanner from b2.util import bjam_signature + __re_hyphen = re.compile ('-') def __register_features (): @@ -98,6 +99,12 @@ def register (type, suffixes = [], base_type = None): feature.compose ('' + type, replace_grist (base_type, '')) feature.compose ('' + type, '' + base_type) + import b2.build.generators as generators + # Adding a new derived type affects generator selection so we need to + # make the generator selection module update any of its cached + # information related to a new derived type being defined. + generators.update_cached_information_with_a_new_type(type) + # FIXME: resolving recursive dependency. from b2.manager import get_manager get_manager().projects().project_rules().add_rule_for_type(type) @@ -142,6 +149,12 @@ def get_scanner (type, prop_set): return None +def base(type): + """Returns a base type for the given type or nothing in case the given type is + not derived.""" + + return __types[type]['base'] + def all_bases (type): """ Returns type and all of its bases, in the order of their distance from type. """ diff --git a/v2/test/generator_selection.py b/v2/test/generator_selection.py index 9616bd5bc..e10cb0d3b 100755 --- a/v2/test/generator_selection.py +++ b/v2/test/generator_selection.py @@ -51,6 +51,28 @@ else } """) + t.write("Other/mygen.py", """ +import b2.build.generators as generators +import b2.build.type as type + +from b2.manager import get_manager + +import os + + +type.register('MY_TYPE', ['extension']) +generators.register_standard('mygen.generate-a-cpp-file', ['MY_TYPE'], ['CPP']) +if os.name == 'nt': + action = 'echo void g() {} > "$(<)"' +else: + action = 'echo "void g() {}" > "$(<)"' +def f(*args): + print "Generating a CPP file..." + +get_manager().engine().register_action("mygen.generate-a-cpp-file", + action, function=f) +""") + t.write("Other/jamfile.jam", """ import mygen ; obj other-obj : source.extension ; diff --git a/v2/util/logger.py b/v2/util/logger.py index a0d7a6e37..de6521290 100644 --- a/v2/util/logger.py +++ b/v2/util/logger.py @@ -30,7 +30,7 @@ class NullLogger: return False def on (self): - return False + return True class TextLogger (NullLogger): def __init__ (self): From 425449f65b38338ebb3e71e8a36dbb05614a2308 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Mon, 2 Aug 2010 15:46:26 +0000 Subject: [PATCH 085/165] Fix a couple typos. [SVN r64542] --- v2/build/generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index 39696def3..405d48d31 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -967,7 +967,7 @@ def find_viable_generators (target_type, prop_set): if not g in __active_generators: viable_generators.append (g) else: - dout(" generator %s is active, discarning" % g.id()) + dout(" generator %s is active, discarding" % g.id()) # Generators which override 'all'. all_overrides = [] @@ -1051,7 +1051,7 @@ def construct (project, name, target_type, prop_set, sources, top_level=False): If 'top-level' is set, does not suppress generators that are already used in the stack. This may be useful in cases where a generator - has to build a metatargets -- for example a target corresponding to + has to build a metatarget -- for example a target corresponding to built tool. """ From d2a23505613d6092e6fef3f8968daf41609e9eb8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 16:53:42 +0000 Subject: [PATCH 086/165] Initial support for making Python module act as project. [SVN r64548] --- v2/build/project.py | 35 +++++++++++++++++++++++++++++------ v2/test/absolute_sources.py | 15 +++++++++++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 0cadc397c..4120a5e9a 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -90,6 +90,8 @@ class ProjectRegistry: # via 'using' and 'import' rules in Jamfiles. self.loaded_tool_modules_ = {} + self.loaded_tool_module_path_ = {} + # Map from project target to the list of # (id,location) pairs corresponding to all 'use-project' # invocations. @@ -403,6 +405,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) attributes = ProjectAttributes(self.manager, location, module_name) self.module2attributes[module_name] = attributes + python_standalone = False if location: attributes.set("source-location", [location], exact=1) elif not module_name in ["test-config", "site-config", "user-config", "project-config"]: @@ -410,8 +413,9 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # so that it can declare targets. This is intended so that you can put # a .jam file in your sources and use it via 'using'. Standard modules # (in 'tools' subdir) may not assume source dir is set. - module = sys.modules[module_name] - attributes.set("source-location", module.__path__, exact=1) + module = sys.modules[module_name] + attributes.set("source-location", self.loaded_tool_module_path_[module_name], exact=1) + python_standalone = True attributes.set("requirements", property_set.empty(), exact=True) attributes.set("usage-requirements", property_set.empty(), exact=True) @@ -420,7 +424,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) attributes.set("project-root", None, exact=True) attributes.set("build-dir", None, exact=True) - self.project_rules_.init_project(module_name) + self.project_rules_.init_project(module_name, python_standalone) jamroot = False @@ -519,6 +523,9 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) """Returns the project which is currently being loaded.""" return self.current_project + def set_current(self, c): + self.current_project = c + def push_current(self, project): """Temporary changes the current project to 'project'. Should be followed by 'pop-current'.""" @@ -663,14 +670,14 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) if not location: self.manager.errors()("Cannot find module '%s'" % name) - mname = "__build_build_temporary__" + mname = name + "__for_jamfile" file = open(location) try: # TODO: this means we'll never make use of .pyc module, # which might be a problem, or not. + self.loaded_tool_module_path_[mname] = location module = imp.load_module(mname, file, os.path.basename(location), (".py", "r", imp.PY_SOURCE)) - del sys.modules[mname] self.loaded_tool_modules_[name] = module return module finally: @@ -896,8 +903,20 @@ class ProjectRules: return self.call_and_report_errors(callable, *args, **kw) return wrapper - def init_project(self, project_module): + def init_project(self, project_module, python_standalone=False): + if python_standalone: + m = sys.modules[project_module] + + for n in self.local_names: + if n != "import_": + setattr(m, n, getattr(self, n)) + + for n in self.rules: + setattr(m, n, self.rules[n]) + + return + for n in self.local_names: # Using 'getattr' here gives us a bound method, # while using self.__dict__[r] would give unbound one. @@ -1051,6 +1070,8 @@ attribute is allowed only for top-level 'project' invocations""") attributes = self.registry.attributes(jamfile_module) location = attributes.get("location") + saved = self.registry.current() + m = self.registry.load_module(py_name, [location]) for f in m.__dict__: @@ -1070,6 +1091,8 @@ attribute is allowed only for top-level 'project' invocations""") for n, l in zip(names_to_import, local_names): self._import_rule(jamfile_module, l, m.__dict__[n]) + + self.registry.set_current(saved) def conditional(self, condition, requirements): """Calculates conditional requirements for multiple requirements diff --git a/v2/test/absolute_sources.py b/v2/test/absolute_sources.py index eca8d5ad2..58e2cf451 100644 --- a/v2/test/absolute_sources.py +++ b/v2/test/absolute_sources.py @@ -52,6 +52,21 @@ local pwd = [ PWD ] ; alias a : $(pwd)/a.cpp ; """) +t.write("standalone.py", """ +from b2.manager import get_manager + +# FIXME: this is ugly as death +get_manager().projects().initialize(__name__) + +import os ; + +# This use of list as parameter is also ugly. +project(['standalone']) + +pwd = os.getcwd() +alias('a', [os.path.join(pwd, 'a.cpp')]) +""") + t.run_build_system() t.expect_addition("bin/$toolset/debug/a.exe") From 80e3957ee8886e2447b934d2911b094d4a082bdd Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 17:30:46 +0000 Subject: [PATCH 087/165] Make test/standalone.py pass. [SVN r64549] --- v2/build/alias.py | 5 ++++- v2/test/standalone.py | 17 +++++++++++++++++ v2/util/__init__.py | 6 ++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/v2/build/alias.py b/v2/build/alias.py index be119dd94..5fdc1b892 100755 --- a/v2/build/alias.py +++ b/v2/build/alias.py @@ -29,6 +29,8 @@ import targets import property_set from b2.manager import get_manager +from b2.util import metatarget + class AliasTarget(targets.BasicTarget): def __init__(self, *args): @@ -43,6 +45,7 @@ class AliasTarget(targets.BasicTarget): # look like 100% alias. return base.add(subvariant.sources_usage_requirements()) +@metatarget def alias(name, sources, requirements=None, default_build=None, usage_requirements=None): project = get_manager().projects().current() targets = get_manager().targets() @@ -51,7 +54,7 @@ def alias(name, sources, requirements=None, default_build=None, usage_requiremen default_build = default_build[0] targets.main_target_alternative(AliasTarget( - name[0], project, + name, project, targets.main_target_sources(sources, name), targets.main_target_requirements(requirements or [], project), targets.main_target_default_build(default_build, project), diff --git a/v2/test/standalone.py b/v2/test/standalone.py index 785bab597..31603fc97 100644 --- a/v2/test/standalone.py +++ b/v2/test/standalone.py @@ -32,6 +32,23 @@ alias x : $(pwd)/../a.cpp ; alias runtime : x ; """) +t.write("standalone.py", """ +from b2.manager import get_manager + +# FIXME: this is ugly as death +get_manager().projects().initialize(__name__) + +import os ; + +# This use of list as parameter is also ugly. +project(['standalone']) + +pwd = os.getcwd() +alias('x', [os.path.join(pwd, '../a.cpp')]) +alias('runtime', ['x']) +""") + + t.write("sub/jamfile.jam", """ stage bin : /standalone//runtime ; """) diff --git a/v2/util/__init__.py b/v2/util/__init__.py index 89da84909..bb3b7e4f5 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -11,6 +11,12 @@ def bjam_signature(s): return wrap +def metatarget(f): + + f.bjam_signature = (["name"], ["sources", "*"], ["requirements", "*"], + ["default_build", "*"], ["usage_requirements", "*"]) + return f + class cached(object): def __init__(self, function): From 67f9726cf1dd4376f140a8895dca69250ac63e8a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 18:46:04 +0000 Subject: [PATCH 088/165] Fix reporting of sources that have no type. [SVN r64550] --- v2/build/generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/build/generators.py b/v2/build/generators.py index 405d48d31..9421b3f25 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -888,7 +888,7 @@ def __ensure_type (targets): """ for t in targets: if not t.type (): - raise BaseException ("target '%s' has no type" % str (t)) + get_manager().errors()("target '%s' has no type" % str (t)) def find_viable_generators_aux (target_type, prop_set): """ Returns generators which can be used to construct target of specified type @@ -1061,7 +1061,7 @@ def construct (project, name, target_type, prop_set, sources, top_level=False): __active_generators = [] global __construct_stack - if __construct_stack: + if not __construct_stack: __ensure_type (sources) __construct_stack.append (1) From 830d71123e66f60a447b1392fe351e7f2395590b Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 18:48:35 +0000 Subject: [PATCH 089/165] Correct bjam signature of type.register [SVN r64551] --- v2/build/type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/build/type.py b/v2/build/type.py index b04547458..2365795e5 100644 --- a/v2/build/type.py +++ b/v2/build/type.py @@ -55,7 +55,7 @@ def reset (): reset () -@bjam_signature((["type"], ["suffixes", "*"], ["base_type"])) +@bjam_signature((["type"], ["suffixes", "*"], ["base_type", "?"])) def register (type, suffixes = [], base_type = None): """ Registers a target type, possibly derived from a 'base-type'. If 'suffixes' are provided, they list all the suffixes that mean a file is of 'type'. From 1c79982c507b277ebd0dadd5aa32e4d5bc7b04a9 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 20:23:00 +0000 Subject: [PATCH 090/165] Fix handling of derived types with empty suffix. [SVN r64552] --- v2/build/type.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/v2/build/type.py b/v2/build/type.py index 2365795e5..3af0d11cf 100644 --- a/v2/build/type.py +++ b/v2/build/type.py @@ -85,7 +85,7 @@ def register (type, suffixes = [], base_type = None): if len (suffixes) > 0: # Generated targets of 'type' will use the first of 'suffixes' - # (this may be overriden) + # (this may be overriden) set_generated_target_suffix (type, [], suffixes [0]) # Specify mapping from suffixes to type @@ -259,7 +259,7 @@ def generated_target_ps_real(is_suffix, type, properties): # Note that if the string is empty (""), but not null, we consider # suffix found. Setting prefix or suffix to empty string is fine. - if result: + if result is not None: found = True type = __types [type]['base'] @@ -273,8 +273,8 @@ def generated_target_ps(is_suffix, type, prop_set): with the specified properties. If not suffix were specified for 'type', returns suffix for base type, if any. """ - key = str(is_suffix) + type + str(prop_set) - v = __target_suffixes_cache.get (key, None) + key = (is_suffix, type, prop_set) + v = __target_suffixes_cache.get(key, None) if not v: v = generated_target_ps_real(is_suffix, type, prop_set.raw()) From d8bfd8d98a9838b3cfb0a6792688d2e5127dd9c2 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 20:24:50 +0000 Subject: [PATCH 091/165] Fix test/suffix.py [SVN r64553] --- v2/test/suffix.py | 17 +++++++++++++++++ v2/tools/common.py | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/v2/test/suffix.py b/v2/test/suffix.py index cb4ad1180..386e36a9d 100644 --- a/v2/test/suffix.py +++ b/v2/test/suffix.py @@ -47,6 +47,23 @@ actions second } """) +t.write("suffixes.py", """ +import b2.build.type as type +import b2.build.generators as generators +import b2.tools.common as common + +from b2.manager import get_manager + +type.register("First", ["first"]) +type.register("Second", [""], "First") + +generators.register_standard("suffixes.second", ["CPP"], ["Second"]) + +get_manager().engine().register_action("suffixes.second", + "%s $(<)" % common.file_creation_command()) + +""") + t.write("jamroot.jam", """ import suffixes ; """) diff --git a/v2/tools/common.py b/v2/tools/common.py index 5fc855663..b0224b1b2 100644 --- a/v2/tools/common.py +++ b/v2/tools/common.py @@ -513,9 +513,9 @@ def file_creation_command(): already exists is unspecified. """ if os_name() == 'NT': - return ["echo. > "] + return "echo. > " else: - return ["touch "] + return "touch " #FIXME: global variable __mkdir_set = set() From a6c648000130302645acaa4ae7f3da042b3093c2 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 2 Aug 2010 21:27:33 +0000 Subject: [PATCH 092/165] Somewhat fix searched libraries. [SVN r64554] --- v2/build/property.py | 11 +++++++---- v2/build/virtual_target.py | 2 +- v2/test/searched_lib.py | 2 +- v2/tools/builtin.py | 21 +++++++++++---------- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/v2/build/property.py b/v2/build/property.py index 633301d60..d3ed168d4 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -26,12 +26,15 @@ class Property(object): __slots__ = ('_feature', '_value', '_condition') - def __init__(self, feature, value, condition = []): - assert(feature.free() or value.find(':') == -1) - self._feature = feature + def __init__(self, f, value, condition = []): + if type(f) == type(""): + f = feature.get(f) + # At present, single property has a single value. + assert type(value) != type([]) + assert(f.free() or value.find(':') == -1) + self._feature = f self._value = value self._condition = condition - def feature(self): return self._feature diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index a7060123f..2e67a53f3 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -879,7 +879,7 @@ class NullAction (Action): actions which create them. """ def __init__ (self, manager, prop_set): - Action.__init__ (self, manager, None, None, prop_set) + Action.__init__ (self, manager, [], None, prop_set) def actualize (self): if not self.actualized_: diff --git a/v2/test/searched_lib.py b/v2/test/searched_lib.py index 4d6d5f198..48d636609 100644 --- a/v2/test/searched_lib.py +++ b/v2/test/searched_lib.py @@ -46,7 +46,7 @@ t.write("jamfile.jam", """ import path ; import project ; -local here = [ project.attribute $(__name__) location ] ; +path-constant here : . ; here = [ path.root $(here) [ path.pwd ] ] ; exe main : main.cpp helper ; diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index cfe475332..bd3594721 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -336,7 +336,7 @@ class SearchedLibTarget (virtual_target.AbstractFileTarget): return self.search_ def actualize_location (self, target): - project.manager ().engine ().add_not_file_target (target) + bjam.call("NOTFILE", target) def path (self): #FIXME: several functions rely on this not being None @@ -578,19 +578,21 @@ 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('') - [ sources.append (project.manager().get_object(x)) for x in lib_sources ] + sources.extend(lib_sources) # Add properties for all searched libraries extra = [] for s in sources: if s.type () == 'SEARCHED_LIB': search = s.search() - extra.append(replace_grist(search, '')) + extra.extend(property.Property('', sp) for sp in search) orig_xdll_path = [] - if prop_set.get('') == ['true'] and type.is_derived(self.target_types_ [0], 'EXE'): + if prop_set.get('') == ['true'] \ + and type.is_derived(self.target_types_ [0], 'EXE'): xdll_path = prop_set.get('') orig_xdll_path = [ replace_grist(x, '') for x in xdll_path ] # It's possible that we have libraries in sources which did not came @@ -670,12 +672,12 @@ class LinkingGenerator (generators.Generator): fst = [] for s in sources: if type.is_derived(s.type(), 'SEARCHED_LIB'): - name = s.real_name() + n = s.real_name() if s.shared(): - fsa.append(name) + fsa.append(n) else: - fst.append(name) + fst.append(n) else: sources2.append(s) @@ -685,9 +687,8 @@ class LinkingGenerator (generators.Generator): add.append("" + '&&'.join(fsa)) if fst: add.append("" + '&&'.join(fst)) - - spawn = generators.Generator.generated_targets(self, sources2,prop_set.add_raw(add), project, name) - + + spawn = generators.Generator.generated_targets(self, sources2, prop_set.add_raw(add), project, name) return spawn From 1ca19a2f604c028a71e3f11ff42fba133ebeedc0 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 3 Aug 2010 17:45:01 +0000 Subject: [PATCH 093/165] Make sure that we correctly find the root project if there's a project-config.jam [SVN r64578] --- v2/tools/boostbook.jam | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/v2/tools/boostbook.jam b/v2/tools/boostbook.jam index 47f8a326c..0c4c0ca68 100644 --- a/v2/tools/boostbook.jam +++ b/v2/tools/boostbook.jam @@ -408,7 +408,8 @@ rule xml-catalog ( ) root-project = [ $(root-project).project-module ] ; while [ project.attribute $(root-project) parent-module ] && - [ project.attribute $(root-project) parent-module ] != user-config + [ project.attribute $(root-project) parent-module ] != user-config && + [ project.attribute $(root-project) parent-module ] != project-config { root-project = [ project.attribute $(root-project) parent-module ] ; } From 0b1ab9d0f33b1727ecdefe2216ae9402a3a764ad Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 3 Aug 2010 17:46:19 +0000 Subject: [PATCH 094/165] Make print more robust. This should fix the regression test failure. [SVN r64579] --- v2/util/print.jam | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/v2/util/print.jam b/v2/util/print.jam index 9db214ed0..708d21aba 100644 --- a/v2/util/print.jam +++ b/v2/util/print.jam @@ -423,7 +423,7 @@ rule check-for-update ( target ) local scanner = [ get-scanner ] ; local file = [ path.native [ modules.binding $(__name__) ] ] ; local g = [ MATCH <(.*)> : $(target:G) ] ; - local dependency-target = $(__file__:G=$(g)-$(target:G=)-$(scanner)) ; + local dependency-target = $(__file__:G=$(g:E=)-$(target:G=)-$(scanner)) ; DEPENDS $(target) : $(dependency-target) ; SEARCH on $(dependency-target) = $(file:D) ; ISFILE $(dependency-target) ; @@ -449,7 +449,11 @@ class print-scanner : scanner local base = [ on $(target) return $(base) ] ; local nl = [ on $(base) return $(nl) ] ; local text-content = [ on $(base) return $(text-content) ] ; - local dir = [ path.make [ on $(base) return $(LOCATE) ] ] ; + local dir = [ on $(base) return $(LOCATE) ] ; + if $(dir) + { + dir = [ path.make $(dir) ] ; + } local file = [ path.native [ path.join $(dir) $(base:G=) ] ] ; local actual-content ; if [ os.name ] = NT From 6bf35112bd992cfadf1132de0272c7951af976e6 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 4 Aug 2010 10:16:08 +0000 Subject: [PATCH 095/165] Port tools/testing.jam. This was scary. [SVN r64592] --- v2/build/engine.py | 16 +- v2/build/errors.py | 5 +- v2/build/generators.py | 8 +- v2/build/targets.py | 2 +- v2/build/toolset.py | 3 +- v2/build/type.py | 5 + v2/build_system.py | 9 +- v2/kernel/bootstrap.jam | 4 +- v2/tools/common.py | 29 +++- v2/tools/testing-aux.jam | 216 +++++++++++++++++++++++++ v2/tools/testing.py | 339 +++++++++++++++++++++++++++++++++++++++ v2/util/__init__.py | 7 + v2/util/option.py | 2 +- v2/util/os_j.py | 7 +- 14 files changed, 625 insertions(+), 27 deletions(-) create mode 100644 v2/tools/testing-aux.jam create mode 100644 v2/tools/testing.py diff --git a/v2/build/engine.py b/v2/build/engine.py index b342fe351..fe63c5760 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -32,12 +32,20 @@ class BjamAction: targets, sources, []) class BjamNativeAction: - """Class representing bjam action fully defined by Jam code.""" + """Class representing bjam action defined by Jam code. + + We still allow to associate a Python callable that will + be called when this action is installed on any target. + """ - def __init__(self, action_name): + def __init__(self, action_name, function): self.action_name = action_name + self.function = function def __call__(self, targets, sources, property_set): + if self.function: + self.function(targets, sources, property_set) + p = [] if property_set: p = property_set.raw() @@ -138,7 +146,7 @@ class Engine: else: return context_module + '%' + action_name - def register_bjam_action (self, action_name): + def register_bjam_action (self, action_name, function=None): """Informs self that 'action_name' is declared in bjam. From this point, 'action_name' is a valid argument to the @@ -151,7 +159,7 @@ class Engine: # can just register them without specially checking if # action is already registered. if not self.actions.has_key(action_name): - self.actions[action_name] = BjamNativeAction(action_name) + self.actions[action_name] = BjamNativeAction(action_name, function) # Overridables diff --git a/v2/build/errors.py b/v2/build/errors.py index 8e17a73c0..d9dceefe0 100644 --- a/v2/build/errors.py +++ b/v2/build/errors.py @@ -60,10 +60,7 @@ class ExceptionWithUserContext(Exception): def report(self): print "error:", self.args[0] if self.original_exception_: - try: - print format(self.original_exception_.args[0], " ") - except: - print format(str(self.original_exception_), " ") + print format(str(self.original_exception_), " ") print print " error context (most recent first):" for c in self.context_[::-1]: diff --git a/v2/build/generators.py b/v2/build/generators.py index 9421b3f25..2c59f7ca1 100644 --- a/v2/build/generators.py +++ b/v2/build/generators.py @@ -581,20 +581,20 @@ class Generator: real_source_type = source.type () # If there are no source types, we can consume anything - source_types = self.source_types + source_types = self.source_types() if not source_types: - source_types = [real_source_type] + source_types = [real_source_type] consumed = [] missing_types = [] - for st in self.source_types_: + for st in source_types: # The 'source' if of right type already) if real_source_type == st or type.is_derived (real_source_type, st): consumed.append (source) else: missing_types.append (st) - + return (consumed, missing_types) def action_class (self): diff --git a/v2/build/targets.py b/v2/build/targets.py index 4cc3f0a98..9483b36e8 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -825,7 +825,7 @@ class BasicTarget (AbstractTarget): if self.source_targets_ == None: self.source_targets_ = [] for s in self.sources_: - self.source_targets_.append (self.resolve_reference (s, self.project_)) + self.source_targets_.append(self.resolve_reference(s, self.project_)[0]) return self.source_targets_ diff --git a/v2/build/toolset.py b/v2/build/toolset.py index 3ad356db3..c5e1fb38f 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -329,8 +329,7 @@ def __handle_flag_value (manager, value, ps): if f.dependency(): # the value of a dependency feature is a target # and must be actualized - # FIXME: verify that 'find' actually works, ick! - result.append (manager.targets ().find(value).actualize ()) + result.append(value.actualize()) elif f.path() or f.free(): diff --git a/v2/build/type.py b/v2/build/type.py index 3af0d11cf..ddb7ba09d 100644 --- a/v2/build/type.py +++ b/v2/build/type.py @@ -109,6 +109,11 @@ def register (type, suffixes = [], base_type = None): from b2.manager import get_manager get_manager().projects().project_rules().add_rule_for_type(type) +# FIXME: quick hack. +def type_from_rule_name(rule_name): + return rule_name.upper().replace("-", "_") + + def register_suffixes (suffixes, type): """ Specifies that targets with suffix from 'suffixes' have the type 'type'. If a different type is already specified for any of syffixes, issues an error. diff --git a/v2/build_system.py b/v2/build_system.py index 9d2f05f26..f779ffb83 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -104,10 +104,10 @@ def set_default_toolset(toolset, version=None): default_toolset_version = version -pre_build_hook = None +pre_build_hook = [] -def set_pre_build_hook(callable): - pre_build_hook = callable +def add_pre_build_hook(callable): + pre_build_hook.append(callable) post_build_hook = None @@ -851,7 +851,8 @@ def main_real(): #configure.print-configure-checks-summary ; if pre_build_hook: - pre_build_hook() + for h in pre_build_hook: + h() bjam.call("DEPENDS", "all", actual_targets) ok = bjam.call("UPDATE_NOW", "all") # FIXME: add out-xml diff --git a/v2/kernel/bootstrap.jam b/v2/kernel/bootstrap.jam index 28ec57348..004784a49 100644 --- a/v2/kernel/bootstrap.jam +++ b/v2/kernel/bootstrap.jam @@ -212,9 +212,9 @@ if ! $(dont-build) } } - rule get-target-variable ( target : variable ) + rule get-target-variable ( targets + : variable ) { - return [ on $(target) return $($(variable)) ] ; + return [ on $(targets) return $($(variable)) ] ; } rule import-rules-from-parent ( parent-module : this-module : user-rules ) diff --git a/v2/tools/common.py b/v2/tools/common.py index b0224b1b2..612745b81 100644 --- a/v2/tools/common.py +++ b/v2/tools/common.py @@ -14,6 +14,7 @@ import re import bjam import os import os.path +import sys from b2.build import feature from b2.util.utility import * @@ -46,9 +47,31 @@ def reset (): __debug_configuration = '--debug-configuration' in bjam.variable('ARGV') __show_configuration = '--show-configuration' in bjam.variable('ARGV') - + + global __executable_path_variable + OS = bjam.call("peek", [], "OS")[0] + 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: + if n.lower() == "path": + __executable_path_variable = n + break + else: + __executable_path_variable = "PATH" + + m = {"NT": __executable_path_variable, + "CYGWIN": "PATH", + "MACOSX": "DYLD_LIBRARY_PATH", + "AIX": "LIBPATH"} + global __shared_library_path_variable + __shared_library_path_variable = m.get(OS, "LD_LIBRARY_PATH") + reset() +def shared_library_path_variable(): + return __shared_library_path_variable + # ported from trunk@47174 class Configurations(object): """ @@ -502,9 +525,9 @@ def prepend_path_variable_command(variable, paths): """ Returns a command that prepends the given paths to the named path variable on the current platform. - """ + """ return path_variable_setting_command(variable, - paths + os.environ(variable).split(os.pathsep)) + paths + os.environ.get(variable, "").split(os.pathsep)) def file_creation_command(): """ diff --git a/v2/tools/testing-aux.jam b/v2/tools/testing-aux.jam new file mode 100644 index 000000000..d55894567 --- /dev/null +++ b/v2/tools/testing-aux.jam @@ -0,0 +1,216 @@ +# This module is imported by testing.py. The definitions here are +# too tricky to do in Python + +# Causes the 'target' to exist after bjam invocation if and only if all the +# dependencies were successfully built. +# +rule expect-success ( target : dependency + : requirements * ) +{ + **passed** $(target) : $(sources) ; +} +IMPORT testing : expect-success : : testing.expect-success ; + +# Causes the 'target' to exist after bjam invocation if and only if all some of +# the dependencies were not successfully built. +# +rule expect-failure ( target : dependency + : properties * ) +{ + local grist = [ MATCH ^<(.*)> : $(dependency:G) ] ; + local marker = $(dependency:G=$(grist)*fail) ; + (failed-as-expected) $(marker) ; + FAIL_EXPECTED $(dependency) ; + LOCATE on $(marker) = [ on $(dependency) return $(LOCATE) ] ; + RMOLD $(marker) ; + DEPENDS $(marker) : $(dependency) ; + DEPENDS $(target) : $(marker) ; + **passed** $(target) : $(marker) ; +} +IMPORT testing : expect-failure : : testing.expect-failure ; + +# The rule/action combination used to report successful passing of a test. +# +rule **passed** +{ + # Force deletion of the target, in case any dependencies failed to build. + RMOLD $(<) ; +} + + +# Used to create test files signifying passed tests. +# +actions **passed** +{ + echo passed > "$(<)" +} + + +# Used to create replacement object files that do not get created during tests +# that are expected to fail. +# +actions (failed-as-expected) +{ + echo failed as expected > "$(<)" +} + +# Runs executable 'sources' and stores stdout in file 'target'. Unless +# --preserve-test-targets command line option has been specified, removes the +# executable. The 'target-to-remove' parameter controls what should be removed: +# - if 'none', does not remove anything, ever +# - if empty, removes 'source' +# - if non-empty and not 'none', contains a list of sources to remove. +# +rule capture-output ( target : source : properties * : targets-to-remove * ) +{ + output-file on $(target) = $(target:S=.output) ; + LOCATE on $(target:S=.output) = [ on $(target) return $(LOCATE) ] ; + + # The INCLUDES kill a warning about independent target... + INCLUDES $(target) : $(target:S=.output) ; + # but it also puts .output into dependency graph, so we must tell jam it is + # OK if it cannot find the target or updating rule. + NOCARE $(target:S=.output) ; + + # This has two-fold effect. First it adds input files to the dependendency + # graph, preventing a warning. Second, it causes input files to be bound + # before target is created. Therefore, they are bound using SEARCH setting + # on them and not LOCATE setting of $(target), as in other case (due to jam + # bug). + DEPENDS $(target) : [ on $(target) return $(INPUT_FILES) ] ; + + if $(targets-to-remove) = none + { + targets-to-remove = ; + } + else if ! $(targets-to-remove) + { + targets-to-remove = $(source) ; + } + + if [ on $(target) return $(REMOVE_TEST_TARGETS) ] + { + TEMPORARY $(targets-to-remove) ; + # Set a second action on target that will be executed after capture + # output action. The 'RmTemps' rule has the 'ignore' modifier so it is + # always considered succeeded. This is needed for 'run-fail' test. For + # that test the target will be marked with FAIL_EXPECTED, and without + # 'ignore' successful execution will be negated and be reported as + # failure. With 'ignore' we do not detect a case where removing files + # fails, but it is not likely to happen. + RmTemps $(target) : $(targets-to-remove) ; + } +} + + +if [ os.name ] = NT +{ + .STATUS = %status% ; + .SET_STATUS = "set status=%ERRORLEVEL%" ; + .RUN_OUTPUT_NL = "echo." ; + .STATUS_0 = "%status% EQU 0 (" ; + .STATUS_NOT_0 = "%status% NEQ 0 (" ; + .VERBOSE = "%verbose% EQU 1 (" ; + .ENDIF = ")" ; + .SHELL_SET = "set " ; + .CATENATE = type ; + .CP = copy ; +} +else +{ + .STATUS = "$status" ; + .SET_STATUS = "status=$?" ; + .RUN_OUTPUT_NL = "echo" ; + .STATUS_0 = "test $status -eq 0 ; then" ; + .STATUS_NOT_0 = "test $status -ne 0 ; then" ; + .VERBOSE = "test $verbose -eq 1 ; then" ; + .ENDIF = "fi" ; + .SHELL_SET = "" ; + .CATENATE = cat ; + .CP = cp ; +} + + +.VERBOSE_TEST = 0 ; +if --verbose-test in [ modules.peek : ARGV ] +{ + .VERBOSE_TEST = 1 ; +} + + +.RM = [ common.rm-command ] ; + + +actions capture-output bind INPUT_FILES output-file +{ + $(PATH_SETUP) + $(LAUNCHER) "$(>)" $(ARGS) "$(INPUT_FILES)" > "$(output-file)" 2>&1 + $(.SET_STATUS) + $(.RUN_OUTPUT_NL) >> "$(output-file)" + echo EXIT STATUS: $(.STATUS) >> "$(output-file)" + if $(.STATUS_0) + $(.CP) "$(output-file)" "$(<)" + $(.ENDIF) + $(.SHELL_SET)verbose=$(.VERBOSE_TEST) + if $(.STATUS_NOT_0) + $(.SHELL_SET)verbose=1 + $(.ENDIF) + if $(.VERBOSE) + echo ====== BEGIN OUTPUT ====== + $(.CATENATE) "$(output-file)" + echo ====== END OUTPUT ====== + $(.ENDIF) + exit $(.STATUS) +} + +IMPORT testing : capture-output : : testing.capture-output ; + + +actions quietly updated ignore piecemeal together RmTemps +{ + $(.RM) "$(>)" +} + + +.MAKE_FILE = [ common.file-creation-command ] ; + +rule unit-test ( target : source : properties * ) +{ + run-path-setup $(target) : $(source) : $(properties) ; +} + + +actions unit-test +{ + $(PATH_SETUP) + $(LAUNCHER) $(>) $(ARGS) && $(.MAKE_FILE) $(<) +} + +rule record-time ( target : source : start end user system ) +{ + local src-string = [$(source:G=:J=",")"] " ; + USER_TIME on $(target) += $(src-string)$(user) ; + SYSTEM_TIME on $(target) += $(src-string)$(system) ; +} + +# Calling this rule requests that Boost Build time how long it taks to build the +# 'source' target and display the results both on the standard output and in the +# 'target' file. +# +rule time ( target : source : properties * ) +{ + # Set up rule for recording timing information. + __TIMING_RULE__ on $(source) = testing.record-time $(target) ; + + # Make sure that the source is rebuilt any time we need to retrieve that + # information. + REBUILDS $(target) : $(source) ; +} + + +actions time +{ + echo user: $(USER_TIME) + echo system: $(SYSTEM_TIME) + + echo user: $(USER_TIME)" seconds" > "$(<)" + echo system: $(SYSTEM_TIME)" seconds" >> "$(<)" +} diff --git a/v2/tools/testing.py b/v2/tools/testing.py new file mode 100644 index 000000000..46eac8b0d --- /dev/null +++ b/v2/tools/testing.py @@ -0,0 +1,339 @@ +# Status: ported, except for --out-xml +# Base revision: 64488 +# +# Copyright 2005 Dave Abrahams +# Copyright 2002, 2003, 2004, 2005, 2010 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 module implements regression testing framework. It declares a number of +# main target rules which perform some action and, if the results are OK, +# creates an output file. +# +# The exact list of rules is: +# 'compile' -- creates .test file if compilation of sources was +# successful. +# 'compile-fail' -- creates .test file if compilation of sources failed. +# 'run' -- creates .test file is running of executable produced from +# sources was successful. Also leaves behind .output file +# with the output from program run. +# 'run-fail' -- same as above, but .test file is created if running fails. +# +# In all cases, presence of .test file is an indication that the test passed. +# For more convenient reporting, you might want to use C++ Boost regression +# testing utilities (see http://www.boost.org/more/regression.html). +# +# For historical reason, a 'unit-test' rule is available which has the same +# syntax as 'exe' and behaves just like 'run'. + +# Things to do: +# - Teach compiler_status handle Jamfile.v2. +# Notes: +# - is not implemented, since it is Como-specific, and it is not +# clear how to implement it +# - std::locale-support is not implemented (it is used in one test). + +import b2.build.feature as feature +import b2.build.type as type +import b2.build.targets as targets +import b2.build.generators as generators +import b2.build.toolset as toolset +import b2.tools.common as common +import b2.util.option as option +import b2.build_system as build_system + + + +from b2.manager import get_manager +from b2.util import stem, bjam_signature +from b2.util.sequence import unique + +import bjam + +import re +import os.path +import sys + +def init(): + pass + +# Feature controling the command used to lanch test programs. +feature.feature("testing.launcher", [], ["free", "optional"]) + +feature.feature("test-info", [], ["free", "incidental"]) +feature.feature("testing.arg", [], ["free", "incidental"]) +feature.feature("testing.input-file", [], ["free", "dependency"]) + +feature.feature("preserve-test-targets", ["on", "off"], ["incidental", "propagated"]) + +# Register target types. +type.register("TEST", ["test"]) +type.register("COMPILE", [], "TEST") +type.register("COMPILE_FAIL", [], "TEST") + +type.register("RUN_OUTPUT", ["run"]) +type.register("RUN", [], "TEST") +type.register("RUN_FAIL", [], "TEST") + +type.register("LINK", [], "TEST") +type.register("LINK_FAIL", [], "TEST") +type.register("UNIT_TEST", ["passed"], "TEST") + +__all_tests = [] + +# Declare the rules which create main targets. While the 'type' module already +# creates rules with the same names for us, we need extra convenience: default +# name of main target, so write our own versions. + +# Helper rule. Create a test target, using basename of first source if no target +# name is explicitly passed. Remembers the created target in a global variable. +def make_test(target_type, sources, requirements, target_name=None): + + if not target_name: + target_name = stem(os.path.basename(sources[0])) + + # Having periods (".") in the target name is problematic because the typed + # generator will strip the suffix and use the bare name for the file + # targets. Even though the location-prefix averts problems most times it + # does not prevent ambiguity issues when referring to the test targets. For + # example when using the XML log output. So we rename the target to remove + # the periods, and provide an alias for users. + real_name = target_name.replace(".", "~") + + project = get_manager().projects().current() + # The forces the build system for generate paths in the + # form '$build_dir/array1.test/gcc/debug'. This is necessary to allow + # post-processing tools to work. + t = get_manager().targets().create_typed_target( + type.type_from_rule_name(target_type), project, real_name, sources, + requirements + ["" + real_name + ".test"], [], []) + + # The alias to the real target, per period replacement above. + if real_name != target_name: + get_manager().projects().project_rules().all_names_["alias"]( + target_name, [t]) + + # Remember the test (for --dump-tests). A good way would be to collect all + # given a project. This has some technical problems: e.g. we can not call + # this dump from a Jamfile since projects referred by 'build-project' are + # not available until the whole Jamfile has been loaded. + __all_tests.append(t) + return t + + +# Note: passing more that one cpp file here is known to fail. Passing a cpp file +# and a library target works. +# +@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"])) +def compile(sources, requirements, target_name=None): + return make_test("compile", sources, requirements, target_name) + +@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"])) +def compile_fail(sources, requirements, target_name=None): + return make_test("compile-fail", sources, requirements, target_name) + +@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"])) +def link(sources, requirements, target_name=None): + return make_test("link", sources, requirements, target_name) + +@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"])) +def link_fail(sources, requirements, target_name=None): + return make_test("link-fail", sources, requirements, target_name) + +def handle_input_files(input_files): + if len(input_files) > 1: + # Check that sorting made when creating property-set instance will not + # change the ordering. + if sorted(input_files) != input_files: + get_manager().errors()("Names of input files must be sorted alphabetically\n" + + "due to internal limitations") + return ["" + f for f in input_files] + +@bjam_signature((["sources", "*"], ["args", "*"], ["input_files", "*"], + ["requirements", "*"], ["target_name", "?"], + ["default_build", "*"])) +def run(sources, args, input_files, requirements, target_name=None, default_build=[]): + if args: + requirements.append("" + " ".join(args)) + requirements.extend(handle_input_files(input_files)) + return make_test("run", sources, requirements, target_name) + +@bjam_signature((["sources", "*"], ["args", "*"], ["input_files", "*"], + ["requirements", "*"], ["target_name", "?"], + ["default_build", "*"])) +def run_fail(sources, args, input_files, requirements, target_name=None, default_build=[]): + if args: + requirements.append("" + " ".join(args)) + requirements.extend(handle_input_files(input_files)) + return make_test("run-fail", sources, requirements, target_name) + +# Register all the rules +for name in ["compile", "compile-fail", "link", "link-fail", "run", "run-fail"]: + get_manager().projects().add_rule(name, getattr(sys.modules[__name__], name.replace("-", "_"))) + +# Use 'test-suite' as a synonym for 'alias', for backward compatibility. +from b2.build.alias import alias +get_manager().projects().add_rule("test-suite", alias) + +# For all main targets in 'project-module', which are typed targets with type +# derived from 'TEST', produce some interesting information. +# +def dump_tests(): + for t in __all_tests: + dump_test(t) + +# Given a project location in normalized form (slashes are forward), compute the +# name of the Boost library. +# +__ln1 = re.compile("/(tools|libs)/(.*)/(test|example)") +__ln2 = re.compile("/(tools|libs)/(.*)$") +__ln3 = re.compile("(/status$)") +def get_library_name(path): + + path = path.replace("\\", "/") + match1 = __ln1.match(path) + match2 = __ln2.match(path) + match3 = __ln3.match(path) + + if match1: + return match1.group(2) + elif match2: + return match2.group(2) + elif match3: + return "" + elif option.get("dump-tests", False, True): + # The 'run' rule and others might be used outside boost. In that case, + # just return the path, since the 'library name' makes no sense. + return path + +# Was an XML dump requested? +__out_xml = option.get("out-xml", False, True) + +# Takes a target (instance of 'basic-target') and prints +# - its type +# - its name +# - comments specified via the property +# - relative location of all source from the project root. +# +def dump_test(target): + type = target.type() + name = target.name() + project = target.project() + + project_root = project.get('project-root') + library = get_library_name(os.path.abspath(project.get('location'))) + if library: + name = library + "/" + name + + sources = target.sources() + source_files = [] + for s in sources: + if isinstance(s, targets.FileReference): + location = os.path.abspath(os.path.join(s.location(), s.name())) + source_files.append(os.path.relpath(location, os.path.abspath(project_root))) + + target_name = project.get('location') + "//" + target.name() + ".test" + + test_info = target.requirements().get('test-info') + test_info = " ".join('"' + ti + '"' for ti in test_info) + + # If the user requested XML output on the command-line, add the test info to + # that XML file rather than dumping them to stdout. + #if $(.out-xml) + #{ +# local nl = " +#" ; +# .contents on $(.out-xml) += +# "$(nl) " +# "$(nl) " +# "$(nl) " +# "$(nl) " +# "$(nl) " +# ; +# } +# else + + source_files = " ".join('"' + s + '"' for s in source_files) + if test_info: + print 'boost-test(%s) "%s" [%s] : %s' % (type, name, test_info, source_files) + else: + print 'boost-test(%s) "%s" : %s' % (type, name, source_files) + +# Register generators. Depending on target type, either 'expect-success' or +# 'expect-failure' rule will be used. +generators.register_standard("testing.expect-success", ["OBJ"], ["COMPILE"]) +generators.register_standard("testing.expect-failure", ["OBJ"], ["COMPILE_FAIL"]) +generators.register_standard("testing.expect-success", ["RUN_OUTPUT"], ["RUN"]) +generators.register_standard("testing.expect-failure", ["RUN_OUTPUT"], ["RUN_FAIL"]) +generators.register_standard("testing.expect-success", ["EXE"], ["LINK"]) +generators.register_standard("testing.expect-failure", ["EXE"], ["LINK_FAIL"]) + +# Generator which runs an EXE and captures output. +generators.register_standard("testing.capture-output", ["EXE"], ["RUN_OUTPUT"]) + +# Generator which creates a target if sources run successfully. Differs from RUN +# in that run output is not captured. The reason why it exists is that the 'run' +# rule is much better for automated testing, but is not user-friendly (see +# http://article.gmane.org/gmane.comp.lib.boost.build/6353). +generators.register_standard("testing.unit-test", ["EXE"], ["UNIT_TEST"]) + +# FIXME: if those calls are after bjam.call, then bjam will crash +# when toolset.flags calls bjam.caller. +toolset.flags("testing.capture-output", "ARGS", [], [""]) +toolset.flags("testing.capture-output", "INPUT_FILES", [], [""]) +toolset.flags("testing.capture-output", "LAUNCHER", [], [""]) + +toolset.flags("testing.unit-test", "LAUNCHER", [], [""]) +toolset.flags("testing.unit-test", "ARGS", [], [""]) + +type.register("TIME", ["time"]) +generators.register_standard("testing.time", [], ["TIME"]) + + +# The following code sets up actions for this module. It's pretty convoluted, +# but the basic points is that we most of actions are defined by Jam code +# contained in testing-aux.jam, which we load into Jam module named 'testing' + +def run_path_setup(target, sources, ps): + + # For testing, we need to make sure that all dynamic libraries needed by the + # test are found. So, we collect all paths from dependency libraries (via + # xdll-path property) and add whatever explicit dll-path user has specified. + # The resulting paths are added to the environment on each test invocation. + dll_paths = ps.get('dll-path') + dll_paths.extend(ps.get('xdll-path')) + dll_paths.extend(bjam.call("get-target-variable", sources, "RUN_PATH")) + dll_paths = unique(dll_paths) + if dll_paths: + bjam.call("set-target-variable", target, common.prepend_path_variable_command( + common.shared_library_path_variable(), dll_paths)) + +def capture_output_setup(target, sources, ps): + run_path_setup(target, sources, ps) + + if ps.get('preserve-test-targets') == ['off']: + bjam.call("set-target-variable", target, "REMOVE_TEST_TARGETS", "1") + +get_manager().engine().register_bjam_action("testing.capture-output", + capture_output_setup) + + +path = os.path.dirname(get_manager().projects().loaded_tool_module_path_[__name__]) +import b2.util.os_j +get_manager().projects().project_rules()._import_rule("testing", "os.name", + b2.util.os_j.name) +import b2.tools.common +get_manager().projects().project_rules()._import_rule("testing", "common.rm-command", + b2.tools.common.rm_command) +get_manager().projects().project_rules()._import_rule("testing", "common.file-creation-command", + b2.tools.common.file_creation_command) + +bjam.call("load", "testing", os.path.join(path, "testing-aux.jam")) + + +for name in ["expect-success", "expect-failure", "unit-test", "time"]: + get_manager().engine().register_bjam_action("testing." + name) + + +if option.get("dump-tests", False, True): + build_system.add_pre_build_hook(dump_tests) diff --git a/v2/util/__init__.py b/v2/util/__init__.py index bb3b7e4f5..044a8429a 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -48,3 +48,10 @@ def call_jam_function(name, *args): args = ("set-update-action", name) + args return bjam.call(*args) + +def stem(filename): + i = filename.find('.') + if i != -1: + return filename[0:i] + else: + return filename diff --git a/v2/util/option.py b/v2/util/option.py index bf0eb2346..3778183ac 100644 --- a/v2/util/option.py +++ b/v2/util/option.py @@ -26,7 +26,7 @@ def get(name, default_value=None, implied_value=None): if matches: return matches[-1] else: - m = b2.util.regex.transform(sys.argv, "--" + re.escape(name)) + m = b2.util.regex.transform(sys.argv, "--(" + re.escape(name) + ")") if m and implied_value: return implied_value elif options.has_key(name): diff --git a/v2/util/os_j.py b/v2/util/os_j.py index 6ad22b85b..f44cca620 100644 --- a/v2/util/os_j.py +++ b/v2/util/os_j.py @@ -9,8 +9,11 @@ # 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 bjam -import os +__OS = bjam.call("peek", [], "OS")[0] +# Return Jam's name of OS to prevent existing code from burning +# when faced with Python naming def name(): - return os.name + return __OS From 5255209e97dffd4511e22d427e6905c7e31ef151 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 4 Aug 2010 10:24:59 +0000 Subject: [PATCH 096/165] Ubreak tests/dll_path.py in non-python mode. [SVN r64593] --- v2/test/dll_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/test/dll_path.py b/v2/test/dll_path.py index 284b80207..f88e06168 100644 --- a/v2/test/dll_path.py +++ b/v2/test/dll_path.py @@ -48,7 +48,7 @@ rule init ( ) { rule __init__ ( ) { - generator.__init__ dll-paths.list : EXE : PATH_LIST ; + generator.__init__ dll_paths.list : EXE : PATH_LIST ; } rule generated-targets ( sources + : property-set : project name ? ) From add5bdf7e0cfe05fa465b2823b502e7fe90d1d1e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 5 Aug 2010 06:22:58 +0000 Subject: [PATCH 097/165] Port build/configure.jam. Also allow to expose Python class to Jam, which fixes tag.py and inline.py testcases. [SVN r64610] --- v2/build/alias.py | 2 +- v2/build/configure.py | 157 +++++++++++++++++++++++++++++++++++++ v2/build/engine.py | 6 +- v2/build/project.py | 3 +- v2/build/property.py | 10 +-- v2/build/property_set.py | 10 +-- v2/build/targets.py | 129 +++++++++++++++--------------- v2/build/virtual_target.py | 28 ++++--- v2/build_system.py | 23 +++--- v2/engine/src/compile.c | 28 ++++++- v2/kernel/bootstrap.jam | 9 +++ v2/manager.py | 22 ------ v2/test/BoostBuild.py | 3 + v2/test/test_all.py | 4 + v2/util/__init__.py | 59 +++++++++++++- 15 files changed, 368 insertions(+), 125 deletions(-) create mode 100644 v2/build/configure.py diff --git a/v2/build/alias.py b/v2/build/alias.py index 5fdc1b892..f83a25bef 100755 --- a/v2/build/alias.py +++ b/v2/build/alias.py @@ -55,7 +55,7 @@ def alias(name, sources, requirements=None, default_build=None, usage_requiremen targets.main_target_alternative(AliasTarget( name, project, - targets.main_target_sources(sources, name), + targets.main_target_sources(sources, name, no_renaming=True), targets.main_target_requirements(requirements or [], project), targets.main_target_default_build(default_build, project), targets.main_target_usage_requirements(usage_requirements or [], project))) diff --git a/v2/build/configure.py b/v2/build/configure.py new file mode 100644 index 000000000..34bc9acd3 --- /dev/null +++ b/v2/build/configure.py @@ -0,0 +1,157 @@ +# Status: ported. +# Base revison: 64488 +# +# Copyright (c) 2010 Vladimir Prus. +# +# Use, modification and distribution is subject to the Boost Software +# License Version 1.0. (See accompanying file LICENSE_1_0.txt or +# http://www.boost.org/LICENSE_1_0.txt) + +# This module defines function to help with two main tasks: +# +# - Discovering build-time configuration for the purposes of adjusting +# build process. +# - Reporting what is built, and how it is configured. + +import b2.build.property as property +import b2.build.property_set as property_set + +import b2.build.targets + +from b2.manager import get_manager +from b2.util.sequence import unique +from b2.util import bjam_signature, value_to_jam + +import bjam +import os + +__width = 30 + +def set_width(width): + global __width + __width = 30 + +__components = [] +__built_components = [] +__component_logs = {} +__announced_checks = False + +__log_file = None +__log_fd = -1 + +def register_components(components): + """Declare that the components specified by the parameter exist.""" + __components.extend(components) + +def components_building(components): + """Declare that the components specified by the parameters will be build.""" + __built_components.extend(components) + +def log_component_configuration(component, message): + """Report something about component configuration that the user should better know.""" + __component_logs.setdefault(component, []).append(message) + +def log_check_result(result): + global __announced_checks + if not __announced_checks: + print "Performing configuration checks" + __announced_checks = True + + print result + +def log_library_search_result(library, result): + log_check_result((" - %(library)s : %(result)s" % locals()).rjust(width)) + + +def print_component_configuration(): + + print "\nComponent configuration:" + for c in __components: + if c in __built_components: + s = "building" + else: + s = "not building" + message = " - %s)" % c + message = message.rjust(__width) + message += " : " + s + for m in __component_logs.get(c, []): + print " -" + m + print "" + +__builds_cache = {} + +def builds(metatarget_reference, project, ps, what): + # Attempt to build a metatarget named by 'metatarget-reference' + # in context of 'project' with properties 'ps'. + # Returns non-empty value if build is OK. + + result = [] + + existing = __builds_cache.get((what, ps), None) + if existing is None: + + result = False + __builds_cache[(what, ps)] = False + + targets = b2.build.targets.generate_from_reference( + metatarget_reference, project, ps).targets() + jam_targets = [] + for t in targets: + jam_targets.append(t.actualize()) + + x = (" - %s" % what).rjust(__width) + if bjam.call("UPDATE_NOW", jam_targets, str(__log_fd), "ignore-minus-n"): + __builds_cache[(what, ps)] = True + result = True + log_check_result("%s: yes" % x) + else: + log_check_result("%s: no" % x) + + return result + else: + return existing + +def set_log_file(log_file_name): + # Called by Boost.Build startup code to specify name of a file + # that will receive results of configure checks. This + # should never be called by users. + global __log_file, __log_fd + dirname = os.path.dirname(log_file_name) + if not os.path.exists(dirname): + os.makedirs(dirname) + # Make sure to keep the file around, so that it's not + # garbage-collected and closed + __log_file = open(log_file_name, "w") + __log_fd = __log_file.fileno() + +# Frontend rules + +class CheckTargetBuildsWorker: + + def __init__(self, target, true_properties, false_properties): + self.target = target + self.true_properties = property.create_from_strings(true_properties) + self.false_properties = property.create_from_strings(false_properties) + + def check(self, ps): + + # FIXME: this should not be hardcoded. Other checks might + # want to consider different set of features as relevant. + toolset = ps.get_properties('toolset')[0] + ps = property_set.create([toolset]) + t = get_manager().targets().current() + p = t.project() + if builds(self.target, p, ps, "%s builds" % self.target): + return self.true_properties + else: + return self.false_properties + +@bjam_signature((["target"], ["true_properties", "*"], ["false_properties", "*"])) +def check_target_builds(target, true_properties, false_properties): + worker = CheckTargetBuildsWorker(target, true_properties, false_properties) + value = value_to_jam(worker.check) + return "" + value + +get_manager().projects().add_rule("check-target-builds", check_target_builds) + + diff --git a/v2/build/engine.py b/v2/build/engine.py index fe63c5760..23fd6e58c 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -50,7 +50,7 @@ class BjamNativeAction: if property_set: p = property_set.raw() - b2.util.call_jam_function(self.action_name, targets, sources, p) + b2.util.set_jam_action(self.action_name, targets, sources, p) action_modifiers = {"updated": 0x01, "together": 0x02, @@ -144,6 +144,10 @@ class Engine: # Rule is already in indirect format return action_name else: + ix = action_name.find('.') + if ix != -1 and action_name[:ix] == context_module: + return context_module + '%' + action_name[ix+1:] + return context_module + '%' + action_name def register_bjam_action (self, action_name, function=None): diff --git a/v2/build/project.py b/v2/build/project.py index 4120a5e9a..d3d978e19 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -650,7 +650,8 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) modules = sys.modules for class_name in modules: parts = class_name.split('.') - if name is class_name or parts[0] == "b2" and parts[-1] == name: + if name is class_name or parts[0] == "b2" \ + and parts[-1] == name.replace("-", "_"): module = modules[class_name] self.loaded_tool_modules_[name] = module return module diff --git a/v2/build/property.py b/v2/build/property.py index d3ed168d4..fece8c6d8 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -273,14 +273,6 @@ def split_conditional (property): return None -# FIXME: this should go -def is_conditional (property): - """ Returns True if a property is conditional. - """ - if __re_colon.search (replace_grist (property, '')): - return True - else: - return False def select (features, properties): """ Selects properties which correspond to any of the given features. @@ -310,7 +302,7 @@ def evaluate_conditionals_in_context (properties, context): else: base.append (p) - result = base + result = base[:] for p in conditional: # Evaluate condition diff --git a/v2/build/property_set.py b/v2/build/property_set.py index 589382423..a8f8597ea 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -303,9 +303,9 @@ class PropertySet: context = self if not self.evaluated_.has_key(context): + # FIXME: figure why the call messes up first parameter self.evaluated_[context] = create( - property.evaluate_conditionals_in_context(self.all_raw_, - context.raw())) + property.evaluate_conditionals_in_context(self.all(), context)) return self.evaluated_[context] @@ -412,6 +412,8 @@ class PropertySet: def get (self, feature): """ Returns all values of 'feature'. """ + if type(feature) == type([]): + feature = feature[0] if not isinstance(feature, b2.build.feature.Feature): feature = b2.build.feature.get(feature) @@ -439,9 +441,5 @@ class PropertySet: return result def __contains__(self, item): - for p in self.all_set_: - if p.feature().name() == "toolset": - print "EXISTING", hash(p), hash(p._feature), hash(p._value), "--", hash(item._feature), has(item._value) - print self.all_set_ return item in self.all_set_ diff --git a/v2/build/targets.py b/v2/build/targets.py index 9483b36e8..3d3668822 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -87,7 +87,6 @@ from b2.build.errors import user_error_checkpoint import b2.build.build_request as build_request import b2.util.set - _re_separate_target_from_properties = re.compile (r'^([^<]*)(/(<.*))?$') class TargetRegistry: @@ -111,7 +110,7 @@ class TargetRegistry: target.project ().add_alternative (target) return target - def main_target_sources (self, sources, main_target_name, no_remaning=0): + def main_target_sources (self, sources, main_target_name, no_renaming=0): """Return the list of sources to use, if main target rule is invoked with 'sources'. If there are any objects in 'sources', they are treated as main target instances, and the name of such targets are adjusted to @@ -120,17 +119,20 @@ class TargetRegistry: result = [] for t in sources: + + t = b2.util.jam_to_value_maybe(t) + if isinstance (t, AbstractTarget): name = t.name () if not no_renaming: - new_name = main_target_name + '__' + name - t.rename (new_name) + name = main_target_name + '__' + name + t.rename (name) # Inline targets are not built by default. p = t.project() p.mark_target_as_explicit(name) - result.append (new_name) + result.append(name) else: result.append (t) @@ -776,6 +778,50 @@ class FileReference (AbstractTarget): return self.file_location_ +def resolve_reference(target_reference, project): + """ Given a target_reference, made in context of 'project', + returns the AbstractTarget instance that is referred to, as well + as properties explicitly specified for this reference. + """ + # Separate target name from properties override + split = _re_separate_target_from_properties.match (target_reference) + if not split: + raise BaseException ("Invalid reference: '%s'" % target_reference) + + id = split.group (1) + + sproperties = [] + + if split.group (3): + sproperties = property.create_from_strings(feature.split(split.group(3))) + sproperties = feature.expand_composites(sproperties) + + # Find the target + target = project.find (id) + + return (target, property_set.create(sproperties)) + +def generate_from_reference(target_reference, project, property_set): + """ Attempts to generate the target given by target reference, which + can refer both to a main target or to a file. + Returns a list consisting of + - usage requirements + - generated virtual targets, if any + target_reference: Target reference + project: Project where the reference is made + property_set: Properties of the main target that makes the reference + """ + target, sproperties = resolve_reference(target_reference, project) + + # Take properties which should be propagated and refine them + # with source-specific requirements. + propagated = property_set.propagated() + rproperties = propagated.refine(sproperties) + + return target.generate(rproperties) + + + class BasicTarget (AbstractTarget): """ Implements the most standard way of constructing main target alternative from sources. Allows sources to be either file or @@ -835,29 +881,6 @@ class BasicTarget (AbstractTarget): def default_build (self): return self.default_build_ - def resolve_reference (self, target_reference, project): - """ Given a target_reference, made in context of 'project', - returns the AbstractTarget instance that is referred to, as well - as properties explicitly specified for this reference. - """ - # Separate target name from properties override - split = _re_separate_target_from_properties.match (target_reference) - if not split: - raise BaseException ("Invalid reference: '%s'" % target_reference) - - id = split.group (1) - - sproperties = [] - - if split.group (3): - sproperties = property.create_from_strings(feature.split(split.group(3))) - sproperties = feature.expand_composites(sproperties) - - # Find the target - target = project.find (id) - - return (target, property_set.create(sproperties)) - def common_properties (self, build_request, requirements): """ Given build request and requirements, return properties common to dependency build request and target build @@ -908,24 +931,23 @@ class BasicTarget (AbstractTarget): # # might come from project's requirements. unconditional = feature.expand(requirements.non_conditional()) - - raw = context.all() - raw = property.refine(raw, unconditional) + + context = context.refine(property_set.create(unconditional)) # We've collected properties that surely must be present in common # properties. We now try to figure out what other properties # should be added in order to satisfy rules (4)-(6) from the docs. - conditionals = requirements.conditional() + conditionals = property_set.create(requirements.conditional()) # It's supposed that #conditionals iterations # should be enough for properties to propagate along conditions in any # direction. - max_iterations = len(conditionals) +\ + max_iterations = len(conditionals.all()) +\ len(requirements.get("")) + 1 added_requirements = [] - current = raw + current = context # It's assumed that ordinary conditional requirements can't add # properties, and that rules referred @@ -933,25 +955,24 @@ class BasicTarget (AbstractTarget): # properties. So the list of indirect conditionals # does not change. indirect = requirements.get("") - indirect = [s[1:] for s in indirect] ok = 0 for i in range(0, max_iterations): - e = property.evaluate_conditionals_in_context(conditionals, current) + e = conditionals.evaluate_conditionals(current).all()[:] # Evaluate indirect conditionals. for i in indirect: + i = b2.util.jam_to_value_maybe(i) if callable(i): # This is Python callable, yeah. - e.extend(bjam.call(i, current)) + e.extend(i(current)) else: # Name of bjam function. Because bjam is unable to handle # list of Property, pass list of strings. - br = b2.util.call_jam_function(i, [str(p) for p in current]) + br = b2.util.call_jam_function(i[1:], [str(p) for p in current.all()]) if br: e.extend(property.create_from_strings(br)) - if e == added_requirements: # If we got the same result, we've found final properties. @@ -963,7 +984,7 @@ class BasicTarget (AbstractTarget): # Recompute 'current' using initial properties and conditional # requirements. added_requirements = e - current = property.refine(raw, feature.expand(e)) + current = context.refine(property_set.create(feature.expand(e))) if not ok: self.manager().errors()("Can't evaluate conditional properties " @@ -973,7 +994,7 @@ class BasicTarget (AbstractTarget): if what == "added": return property_set.create(unconditional + added_requirements) elif what == "refined": - return property_set.create(current) + return current else: self.manager().errors("Invalid value of the 'what' parameter") @@ -1029,7 +1050,7 @@ class BasicTarget (AbstractTarget): usage_requirements = [] for id in target_ids: - result = self.generate_from_reference(id, self.project_, property_set) + result = generate_from_reference(id, self.project_, property_set) targets += result.targets() usage_requirements += result.usage_requirements().all() @@ -1046,7 +1067,7 @@ class BasicTarget (AbstractTarget): usage_requirements = [] for p in properties: - result = self.generate_from_reference(p.value(), self.project_, ps) + result = generate_from_reference(p.value(), self.project_, ps) for t in result.targets(): result_properties.append(property.Property(p.feature(), t)) @@ -1180,25 +1201,6 @@ class BasicTarget (AbstractTarget): self.manager().targets().decrease_indent() return self.generated_[ps] - - def generate_from_reference (self, target_reference, project, property_set): - """ Attempts to generate the target given by target reference, which - can refer both to a main target or to a file. - Returns a list consisting of - - usage requirements - - generated virtual targets, if any - target_reference: Target reference - project: Project where the reference is made - property_set: Properties of the main target that makes the reference - """ - target, sproperties = self.resolve_reference(target_reference, project) - - # Take properties which should be propagated and refine them - # with source-specific requirements. - propagated = property_set.propagated() - rproperties = propagated.refine(sproperties) - - return target.generate(rproperties) def compute_usage_requirements (self, subvariant): """ Given the set of generated targets, and refined build @@ -1276,6 +1278,9 @@ class TypedTarget (BasicTarget): def __init__ (self, name, project, type, sources, requirements, default_build, usage_requirements): BasicTarget.__init__ (self, name, project, sources, requirements, default_build, usage_requirements) self.type_ = type + + def __jam_repr__(self): + return b2.util.value_to_jam(self) def type (self): return self.type_ diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 2e67a53f3..6d9c65ebf 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -78,6 +78,7 @@ import b2.build.property_set as property_set import b2.build.property as property from b2.manager import get_manager +from b2.util import bjam_signature __re_starts_with_at = re.compile ('^@(.*)') @@ -533,16 +534,22 @@ class AbstractFileTarget (VirtualTarget): if tag: - rule_names = [t[:1] for t in tag if t[0] == '@'] - if rule_names: - if len(tag) > 1: - self.manager_.errors()( -"""@rulename is present but is not the only feature""") - - self.name_ = bjam.call(rule_names[0], specified_name, self.type_, ps) - else: + if len(tag) > 1: self.manager_.errors()( -"""The value of the feature must be '@rule-nane'""") + """@rulename is present but is not the only feature""") + + tag = tag[0] + if callable(tag): + self.name_ = tag(specified_name, self.type_, ps) + else: + if not tag[0] == '@': + self.manager_.errors()("""The value of the feature must be '@rule-nane'""") + + exported_ps = b2.util.value_to_jam(ps, methods=True) + self.name_ = b2.util.call_jam_function( + tag[1:], specified_name, self.type_, exported_ps) + if self.name_: + self.name_ = self.name_[0] # If there's no tag or the tag rule returned nothing. if not tag or not self.name_: @@ -571,10 +578,13 @@ class AbstractFileTarget (VirtualTarget): return name +@bjam_signature((["specified_name"], ["type"], ["property_set"])) def add_prefix_and_suffix(specified_name, type, property_set): """Appends the suffix appropriate to 'type/property-set' combination to the specified name and returns the result.""" + property_set = b2.util.jam_to_value_maybe(property_set) + suffix = "" if type: suffix = b2.build.type.generated_target_suffix(type, property_set) diff --git a/v2/build_system.py b/v2/build_system.py index f779ffb83..f6bb89f6f 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -460,6 +460,8 @@ def main_real(): global_build_dir = option.get("build-dir") manager = Manager(engine, global_build_dir) + import b2.build.configure as configure + if "--version" in sys.argv: version.report() @@ -587,17 +589,18 @@ def main_real(): ## { ## generators.dump ; ## } + - ## # We wish to put config.log in the build directory corresponding - ## # to Jamroot, so that the location does not differ depending on - ## # directory where we do build. The amount of indirection necessary - ## # here is scary. - ## local first-project = [ $(targets[0]).project ] ; - ## local first-project-root-location = [ $(first-project).get project-root ] ; - ## local first-project-root-module = [ project.load $(first-project-root-location) ] ; - ## local first-project-root = [ project.target $(first-project-root-module) ] ; - ## local first-build-build-dir = [ $(first-project-root).build-dir ] ; - ## configure.set-log-file $(first-build-build-dir)/config.log ; + # We wish to put config.log in the build directory corresponding + # to Jamroot, so that the location does not differ depending on + # directory where we do build. The amount of indirection necessary + # here is scary. + first_project = targets[0].project() + first_project_root_location = first_project.get('project-root') + first_project_root_module = manager.projects().load(first_project_root_location) + first_project_root = manager.projects().target(first_project_root_module) + first_build_build_dir = first_project_root.build_dir() + configure.set_log_file(os.path.join(first_build_build_dir, "config.log")) virtual_targets = [] diff --git a/v2/engine/src/compile.c b/v2/engine/src/compile.c index a4106bf39..c79c8febf 100644 --- a/v2/engine/src/compile.c +++ b/v2/engine/src/compile.c @@ -856,9 +856,31 @@ call_python_function(RULE* r, FRAME* frame) } else { - /* Do nothing. 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. */ + /* See if this is an instance that defines special __jam_repr__ + method. */ + if (PyInstance_Check(py_result) + && PyObject_HasAttrString(py_result, "__jam_repr__")) + { + PyObject* repr = PyObject_GetAttrString(py_result, "__jam_repr__"); + if (repr) + { + PyObject* arguments2 = PyTuple_New(0); + PyObject* py_result2 = PyObject_Call(repr, arguments2, 0); + Py_DECREF(repr); + Py_DECREF(arguments2); + if (PyString_Check(py_result2)) + { + result = list_new(0, newstr(PyString_AsString(py_result2))); + } + Py_DECREF(py_result2); + } + } + + /* If 'result' is still empty, do nothing. 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. */ } Py_DECREF( py_result ); diff --git a/v2/kernel/bootstrap.jam b/v2/kernel/bootstrap.jam index 004784a49..c345ba705 100644 --- a/v2/kernel/bootstrap.jam +++ b/v2/kernel/bootstrap.jam @@ -187,6 +187,15 @@ if ! $(dont-build) DEPENDS all : $(targets) ; } + rule call-in-module ( m : rulename : * ) + { + module $(m) + { + return [ $(2) $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ; + } + } + + rule set-update-action ( action : targets * : sources * : properties * ) { $(action) $(targets) : $(sources) : $(properties) ; diff --git a/v2/manager.py b/v2/manager.py index 7067dc82c..473857fc7 100644 --- a/v2/manager.py +++ b/v2/manager.py @@ -38,12 +38,6 @@ class Manager: self.errors_ = Errors() self.command_line_free_features_ = property_set.empty() - # Object Map. - # TODO: This is a kludge: maps object names to the actual instances. - # Sometimes, objects are stored in properties, along with some grist. - # This map is used to store the value and return an id, which can be later on used to retriev it back. - self.object_map_ = {} - global the_manager the_manager = self @@ -86,22 +80,6 @@ class Manager: def set_command_line_free_features(self, v): self.command_line_free_features_ = v - def register_object (self, value): - """ Stores an object in a map and returns a key that can be used to retrieve it. - """ - key = 'object_registry_' + str (value) - self.object_map_ [key] = value - return key - - def get_object (self, key): - """ Returns a previously registered object. - """ - if not isinstance (key, str): - # Probably it's the object itself. - return key - - return self.object_map_ [key] - def construct (self, properties = [], targets = []): """ Constructs the dependency graph. properties: the build properties. diff --git a/v2/test/BoostBuild.py b/v2/test/BoostBuild.py index e9756342e..7c01b6102 100644 --- a/v2/test/BoostBuild.py +++ b/v2/test/BoostBuild.py @@ -46,6 +46,9 @@ def flush_annotations(xml=0): print_annotation(ann[0], ann[1], xml) annotations = [] +def clear_annotations(): + global annotations + annotations = [] defer_annotations = 0 diff --git a/v2/test/test_all.py b/v2/test/test_all.py index fad67fab6..59476bd74 100644 --- a/v2/test/test_all.py +++ b/v2/test/test_all.py @@ -64,6 +64,10 @@ def run_tests(critical_tests, other_tests): print "PASSED" else: print "FAILED" + + if i == "regression": + BoostBuild.flush_annotations() + BoostBuild.clear_annotations() else: rs = "succeed" if not passed: diff --git a/v2/util/__init__.py b/v2/util/__init__.py index 044a8429a..99d34cdd0 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -1,6 +1,7 @@ import bjam import re +import types # Decorator the specifies bjam-side prototype for a Python function def bjam_signature(s): @@ -39,7 +40,7 @@ def unquote(s): _extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)") -def call_jam_function(name, *args): +def set_jam_action(name, *args): m = _extract_jamfile_and_rule.match(name) if m: @@ -49,6 +50,62 @@ def call_jam_function(name, *args): return bjam.call(*args) + +def call_jam_function(name, *args): + + m = _extract_jamfile_and_rule.match(name) + if m: + args = ("call-in-module", m.group(1), m.group(2)) + args + return bjam.call(*args) + else: + return bjam.call(*((name,) + args)) + +__value_id = 0 +__python_to_jam = {} +__jam_to_python = {} + +def value_to_jam(value, methods=False): + """Makes a token to refer to a Python value inside Jam language code. + + The token is merely a string that can be passed around in Jam code and + eventually passed back. For example, we might want to pass PropertySet + instance to a tag function and it might eventually call back + to virtual_target.add_suffix_and_prefix, passing the same instance. + + For values that are classes, we'll also make class methods callable + from Jam. + + Note that this is necessary to make a bit more of existing Jamfiles work. + This trick should not be used to much, or else the performance benefits of + Python port will be eaten. + """ + + global __value_id + + r = __python_to_jam.get(value, None) + if r: + return r + + exported_name = '###_' + str(__value_id) + __value_id = __value_id + 1 + __python_to_jam[value] = exported_name + __jam_to_python[exported_name] = value + + if methods and type(value) == types.InstanceType: + for field_name in dir(value): + field = getattr(value, field_name) + if callable(field) and not field_name.startswith("__"): + bjam.import_rule("", exported_name + "." + field_name, field) + + return exported_name + +def jam_to_value_maybe(jam_value): + + if type(jam_value) == type("") and jam_value.startswith("###"): + return __jam_to_python[jam_value] + else: + return jam_value + def stem(filename): i = filename.find('.') if i != -1: From 76c6464ece9ec84025cebdb8cd0c1a9a7a8efe93 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 5 Aug 2010 09:11:17 +0000 Subject: [PATCH 098/165] Remove unused bits [SVN r64613] --- v2/test/searched_lib.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/v2/test/searched_lib.py b/v2/test/searched_lib.py index 48d636609..efbca36ca 100644 --- a/v2/test/searched_lib.py +++ b/v2/test/searched_lib.py @@ -46,9 +46,6 @@ t.write("jamfile.jam", """ import path ; import project ; -path-constant here : . ; -here = [ path.root $(here) [ path.pwd ] ] ; - exe main : main.cpp helper ; lib helper : helper.cpp test_lib ; lib test_lib : : test_lib lib ; @@ -82,9 +79,6 @@ import testing ; project : requirements false ; -local here = [ project.attribute $(__name__) location ] ; -here = [ path.root $(here) [ path.pwd ] ] ; - unit-test main : main.cpp helper ; lib helper : helper.cpp test_lib ; lib test_lib : : test_lib lib ; From bb3119c850852677bbc8e01ad54ba911b649191e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 08:40:42 +0000 Subject: [PATCH 099/165] Fix lots of things. [SVN r64625] --- v2/build/project.py | 6 +- v2/test/project_root_constants.py | 5 +- v2/tools/builtin.py | 91 ++++++++++++++----------------- v2/tools/gcc.py | 2 + v2/tools/testing-aux.jam | 6 -- v2/tools/testing.py | 9 ++- 6 files changed, 56 insertions(+), 63 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index d3d978e19..52268c693 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -859,7 +859,7 @@ class ProjectRules: def add_rule_for_type(self, type): rule_name = type.lower().replace("_", "-") - def xpto (name, sources, requirements = [], default_build = None, usage_requirements = []): + def xpto (name, sources = [], requirements = [], default_build = None, usage_requirements = []): return self.manager_.targets().create_typed_target( type, self.registry.current(), name[0], sources, requirements, default_build, usage_requirements) @@ -991,13 +991,15 @@ attribute is allowed only for top-level 'project' invocations""") Project global constants are normal variables but should not be changed. They are applied to every child Jamfile.""" m = "Jamfile" - self.registry.current().add_constant(name[0], value[0]) + self.registry.current().add_constant(name[0], value) def path_constant(self, name, value): """Declare and set a project global constant, whose value is a path. The path is adjusted to be relative to the invocation directory. The given value path is taken to be either absolute, or relative to this project root.""" + if len(value) > 1: + self.registry.manager.error()("path constant should have one element") self.registry.current().add_constant(name[0], value[0], path=1) def use_project(self, id, where): diff --git a/v2/test/project_root_constants.py b/v2/test/project_root_constants.py index cd8a7d6c7..400c78b4a 100644 --- a/v2/test/project_root_constants.py +++ b/v2/test/project_root_constants.py @@ -56,10 +56,11 @@ ECHO "d2: $(BAR)" ; hello ; """) -t.run_build_system(subdir="d/d2", stdout="""d: foo +t.run_build_system(subdir="d/d2") +t.fail_test(t.stdout().find("""d: foo d2: foo d2: bar Hello 10 -""") +""") == -1) t.cleanup() diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index bd3594721..8156a032b 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -8,6 +8,8 @@ """ Defines standard features and rules. """ +import b2.build.targets as targets + import sys from b2.build import feature, property, virtual_target, generators, type, property_set, scanner from b2.util.utility import * @@ -401,6 +403,7 @@ class LibGenerator (generators.Generator): generators.Generator.__init__(self, id, composing, source_types, target_types_and_names, requirements) def run(self, project, name, prop_set, sources): + # The lib generator is composing, and can be only invoked with # explicit name. This check is present in generator.run (and so in # builtin.LinkingGenerator), but duplicate it here to avoid doing @@ -431,55 +434,42 @@ class LibGenerator (generators.Generator): generators.register(LibGenerator()) -### # The implementation of the 'lib' rule. Beyond standard syntax that rule allows -### # simplified: -### # lib a b c ; -### # so we need to write code to handle that syntax. -### rule lib ( names + : sources * : requirements * : default-build * -### : usage-requirements * ) -### { -### local project = [ project.current ] ; -### -### # This is a circular module dependency, so it must be imported here -### import targets ; -### -### local result ; -### if ! $(sources) && ! $(requirements) -### && ! $(default-build) && ! $(usage-requirements) -### { -### for local name in $(names) -### { -### result += [ -### targets.main-target-alternative -### [ new typed-target $(name) : $(project) : LIB -### : -### : [ targets.main-target-requirements $(requirements) $(name) : -### $(project) ] -### : [ targets.main-target-default-build $(default-build) : $(project) ] -### : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ] -### ] ] ; -### } -### } -### else -### { -### if $(names[2]) -### { -### errors.user-error "When several names are given to the 'lib' rule" : -### "it's not allowed to specify sources or requirements. " ; -### } -### -### local name = $(names[1]) ; -### result = [ targets.main-target-alternative -### [ new typed-target $(name) : $(project) : LIB -### : [ targets.main-target-sources $(sources) : $(name) ] -### : [ targets.main-target-requirements $(requirements) : $(project) ] -### : [ targets.main-target-default-build $(default-build) : $(project) ] -### : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ] -### ] ] ; -### } -### return $(result) ; -### } -### IMPORT $(__name__) : lib : : lib ; +def lib(names, sources=[], requirements=[], default_build=[], usage_requirements=[]): + """The implementation of the 'lib' rule. Beyond standard syntax that rule allows + simplified: 'lib a b c ;'.""" + + if len(names) > 1: + if any(r.startswith('') for r in requirements): + get_manager().errors()("When several names are given to the 'lib' rule\n" + + "it is not allowed to specify the feature.") + + if sources: + get_manager().errors()("When several names are given to the 'lib' rule\n" + + "it is not allowed to specify sources.") + + project = get_manager().projects().current() + result = [] + + for name in names: + r = requirements[:] + + # Support " lib a ; " and " lib a b c ; " syntax. + if not sources and not any(r.startswith("") for r in requirements) \ + and not any(r.startswith("" + name) + + result.append(targets.create_typed_metatarget(name, "LIB", sources, + r, + default_build, + usage_requirements)) + # Ideally, we're return the list of targets, but at present, + # bjam, when give a list of non-strings, emits a warning. It + # should be modified to try calling __jam_repr__ on each + # element of the string, but that's for future. + #return [result] + +get_manager().projects().add_rule("lib", lib) + # Updated to trunk@47077 class SearchedLibGenerator (generators.Generator): @@ -492,6 +482,7 @@ class SearchedLibGenerator (generators.Generator): generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) def run(self, project, name, prop_set, sources): + if not name: return None @@ -607,7 +598,7 @@ class LinkingGenerator (generators.Generator): location = path.root(s.name(), p.get('source-location')) xdll_path.append(path.parent(location)) - extra += [ replace_grist(x, '') for x in xdll_path ] + extra.extend(property.Property('', sp) for sp in xdll_path) if extra: prop_set = prop_set.add_raw (extra) diff --git a/v2/tools/gcc.py b/v2/tools/gcc.py index 4f171d65f..2a3e675ef 100644 --- a/v2/tools/gcc.py +++ b/v2/tools/gcc.py @@ -641,6 +641,8 @@ def gcc_link_dll(targets, sources, properties): engine = get_manager().engine() engine.set_target_variable(targets, 'SPACE', ' ') engine.set_target_variable(targets, 'JAM_SEMAPHORE', 'gcc-link-semaphore') + engine.set_target_variable(targets, "HAVE_SONAME", HAVE_SONAME) + engine.set_target_variable(targets, "SONAME_OPTION", SONAME_OPTION) engine.register_action( 'gcc.link.dll', diff --git a/v2/tools/testing-aux.jam b/v2/tools/testing-aux.jam index d55894567..525dafd0c 100644 --- a/v2/tools/testing-aux.jam +++ b/v2/tools/testing-aux.jam @@ -172,12 +172,6 @@ actions quietly updated ignore piecemeal together RmTemps .MAKE_FILE = [ common.file-creation-command ] ; -rule unit-test ( target : source : properties * ) -{ - run-path-setup $(target) : $(source) : $(properties) ; -} - - actions unit-test { $(PATH_SETUP) diff --git a/v2/tools/testing.py b/v2/tools/testing.py index 46eac8b0d..3b53500cc 100644 --- a/v2/tools/testing.py +++ b/v2/tools/testing.py @@ -305,8 +305,9 @@ def run_path_setup(target, sources, ps): dll_paths.extend(bjam.call("get-target-variable", sources, "RUN_PATH")) dll_paths = unique(dll_paths) if dll_paths: - bjam.call("set-target-variable", target, common.prepend_path_variable_command( - common.shared_library_path_variable(), dll_paths)) + bjam.call("set-target-variable", target, "PATH_SETUP", + common.prepend_path_variable_command( + common.shared_library_path_variable(), dll_paths)) def capture_output_setup(target, sources, ps): run_path_setup(target, sources, ps) @@ -331,9 +332,11 @@ get_manager().projects().project_rules()._import_rule("testing", "common.file-cr bjam.call("load", "testing", os.path.join(path, "testing-aux.jam")) -for name in ["expect-success", "expect-failure", "unit-test", "time"]: +for name in ["expect-success", "expect-failure", "time"]: get_manager().engine().register_bjam_action("testing." + name) +get_manager().engine().register_bjam_action("testing.unit-test", + run_path_setup) if option.get("dump-tests", False, True): build_system.add_pre_build_hook(dump_tests) From 8db37d8482e3c621969bb3a7b08eb12c09e96e0b Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 10:52:45 +0000 Subject: [PATCH 100/165] Port tools/symlink.py [SVN r64633] --- v2/tools/builtin.py | 1 + v2/tools/symlink.py | 112 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 v2/tools/symlink.py diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index 8156a032b..a5e4e9228 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -718,3 +718,4 @@ class ArchiveGenerator (generators.Generator): get_manager().projects().add_rule("variant", variant) import stage +import symlink diff --git a/v2/tools/symlink.py b/v2/tools/symlink.py new file mode 100644 index 000000000..6345ded6d --- /dev/null +++ b/v2/tools/symlink.py @@ -0,0 +1,112 @@ +# Status: ported. +# Base revision: 64488. + +# Copyright 2003 Dave Abrahams +# Copyright 2002, 2003 Rene Rivera +# Copyright 2002, 2003, 2004, 2005 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Defines the "symlink" special target. 'symlink' targets make symbolic links +# to the sources. + +import b2.build.feature as feature +import b2.build.targets as targets +import b2.build.property_set as property_set +import b2.build.virtual_target as virtual_target +import b2.build.targets + +from b2.manager import get_manager + +import bjam + +import os + + +feature.feature("symlink-location", ["project-relative", "build-relative"], ["incidental"]) + +class SymlinkTarget(targets.BasicTarget): + + _count = 0 + + def __init__(self, project, targets, sources): + + # Generate a fake name for now. Need unnamed targets eventually. + fake_name = "symlink#%s" % SymlinkTarget._count + SymlinkTarget._count = SymlinkTarget._count + 1 + + b2.build.targets.BasicTarget.__init__(self, fake_name, project, sources) + + # Remember the targets to map the sources onto. Pad or truncate + # to fit the sources given. + assert len(targets) <= len(sources) + self.targets = targets[:] + sources[len(targets):] + + # The virtual targets corresponding to the given targets. + self.virtual_targets = [] + + def construct(self, name, source_targets, ps): + i = 0 + for t in source_targets: + s = self.targets[i] + a = virtual_target.Action(self.manager(), [t], "symlink.ln", ps) + vt = virtual_target.FileTarget(os.path.basename(s), t.type(), self.project(), a) + + # Place the symlink in the directory relative to the project + # location, instead of placing it in the build directory. + if not ps.get('symlink-location') == "project-relative": + vt.set_path(os.path.join(self.project().get('location'), os.path.dirname(s))) + + vt = get_manager().virtual_targets().register(vt) + self.virtual_targets.append(vt) + i = i + 1 + + return (property_set.empty(), self.virtual_targets) + +# Creates a symbolic link from a set of targets to a set of sources. +# The targets and sources map one to one. The symlinks generated are +# limited to be the ones given as the sources. That is, the targets +# are either padded or trimmed to equate to the sources. The padding +# is done with the name of the corresponding source. For example:: +# +# symlink : one two ; +# +# Is equal to:: +# +# symlink one two : one two ; +# +# Names for symlink are relative to the project location. They cannot +# include ".." path components. +def symlink(targets, sources): + + from b2.manager import get_manager + t = get_manager().targets() + p = get_manager().projects().current() + + return t.main_target_alternative( + SymlinkTarget(p, targets, + # Note: inline targets are not supported for symlink, intentionally, + # since it's used to linking existing non-local targets. + sources)) + + +def setup_ln(targets, sources, ps): + + source_path = bjam.call("get-target-variable", sources[0], "LOCATE")[0] + target_path = bjam.call("get-target-variable", targets[0], "LOCATE")[0] + rel = os.path.relpath(source_path, target_path) + if rel == ".": + bjam.call("set-target-variable", targets, "PATH_TO_SOURCE", "") + else: + bjam.call("set-target-variable", targets, "PATH_TO_SOURCE", rel) + +if os.name == 'nt': + ln_action = """echo "NT symlinks not supported yet, making copy" +del /f /q "$(<)" 2>nul >nul +copy "$(>)" "$(<)" $(NULL_OUT)""" +else: + ln_action = "ln -f -s '$(>:D=:R=$(PATH_TO_SOURCE))' '$(<)'" + +get_manager().engine().register_action("symlink.ln", ln_action, function=setup_ln) + +get_manager().projects().add_rule("symlink", symlink) From 26cf96945991f4dfe4a3e95b9ec80b04672aa021 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 11:22:42 +0000 Subject: [PATCH 101/165] Handle list of instances with __jam_repr__ method returned from Python. This re-fixes test/inline.py broken by 'lib' changes. [SVN r64634] --- v2/engine/src/compile.c | 92 ++++++++++++++++++++++++----------------- v2/tools/builtin.py | 6 +-- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/v2/engine/src/compile.c b/v2/engine/src/compile.c index c79c8febf..2c049aae5 100644 --- a/v2/engine/src/compile.c +++ b/v2/engine/src/compile.c @@ -770,6 +770,45 @@ enter_rule( char *rulename, module_t *target_module ); 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) { @@ -835,52 +874,31 @@ call_python_function(RULE* r, FRAME* frame) for ( i = 0; i < size; ++i ) { PyObject * item = PyList_GetItem( py_result, i ); - if ( PyString_Check( item ) ) - { - result = list_new( result, - newstr( PyString_AsString( item ) ) ); - } - else - { + 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 (PyString_Check(py_result)) - { - result = list_new (0, newstr (PyString_AsString(py_result))); - } else if ( py_result == Py_None ) { result = L0; } - else + else { - /* See if this is an instance that defines special __jam_repr__ - method. */ - if (PyInstance_Check(py_result) - && PyObject_HasAttrString(py_result, "__jam_repr__")) - { - PyObject* repr = PyObject_GetAttrString(py_result, "__jam_repr__"); - if (repr) - { - PyObject* arguments2 = PyTuple_New(0); - PyObject* py_result2 = PyObject_Call(repr, arguments2, 0); - Py_DECREF(repr); - Py_DECREF(arguments2); - if (PyString_Check(py_result2)) - { - result = list_new(0, newstr(PyString_AsString(py_result2))); - } - Py_DECREF(py_result2); - } - } - - /* If 'result' is still empty, do nothing. 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. */ + 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 ); diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index a5e4e9228..c0142db98 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -462,11 +462,7 @@ def lib(names, sources=[], requirements=[], default_build=[], usage_requirements r, default_build, usage_requirements)) - # Ideally, we're return the list of targets, but at present, - # bjam, when give a list of non-strings, emits a warning. It - # should be modified to try calling __jam_repr__ on each - # element of the string, but that's for future. - #return [result] + return result get_manager().projects().add_rule("lib", lib) From f5195fc1c3723ce13b141539c64bc8a00f501693 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 12:32:34 +0000 Subject: [PATCH 102/165] Fix alternative selection and some error reporting and a test. [SVN r64635] --- v2/build/targets.py | 16 ++++++++-------- v2/build_system.py | 11 ++++++----- v2/test/custom_generator.py | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/v2/build/targets.py b/v2/build/targets.py index 3d3668822..f439dd1a5 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -200,7 +200,8 @@ class TargetRegistry: for t in self.targets_being_built_.values(): names.append (t.full_name()) - raise Recursion ("Recursion in main target references" + get_manager().errors()( + "Recursion in main target references\n" "the following target are being built currently: '%s'" % names) self.targets_being_built_[id(main_target_instance)] = main_target_instance @@ -667,7 +668,7 @@ class MainTarget (AbstractTarget): for v in self.alternatives_: properties = v.match (property_set, debug) - if properties: + if properties is not None: if not best: best = v best_properties = properties @@ -725,12 +726,11 @@ class MainTarget (AbstractTarget): best_alternative = self.__select_alternatives (prop_set, debug=0) if not best_alternative: - self.__select_alternatives(prop_set, debug=1) - raise NoBestMatchingAlternative ( - "Failed to build '%s'\n" - "with properties '%s'\n" - "because no best-matching alternative could be found." - % (self.full_name(), prop_set)) + # FIXME: revive. + # self.__select_alternatives(prop_set, debug=1) + self.manager_.errors()( + "No best alternative for '%s'.\n" + % (self.full_name(),)) result = best_alternative.generate (prop_set) diff --git a/v2/build_system.py b/v2/build_system.py index f6bb89f6f..6e33bee77 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -155,16 +155,17 @@ _target_id_split = re.compile("(.*)//(.*)") # code in project-target.find but we can not reuse that code without a # project-targets instance. # -def _find_target(target_id): +def find_target(target_id): - m = _target_id_split(target_id) + projects = get_manager().projects() + m = _target_id_split.match(target_id) if m: - pm = project.find(m.group(1), ".") + pm = projects.find(m.group(1), ".") else: - pm = project.find(target_id, ".") + pm = projects.find(target_id, ".") if pm: - result = project.target(pm) + result = projects.target(pm) if m: result = result.find(m.group(2)) diff --git a/v2/test/custom_generator.py b/v2/test/custom_generator.py index a3395c7e8..9a1188a03 100644 --- a/v2/test/custom_generator.py +++ b/v2/test/custom_generator.py @@ -36,6 +36,23 @@ rule resource-compile ( targets * : sources * : properties * ) generators.register-standard rcc.resource-compile : RCC : OBJ ; """) +t.write("rcc.py", """ +import b2.build.type as type +import b2.build.generators as generators + +from b2.manager import get_manager + +# Use 'RCC' to avoid conflicts with definitions in the standard rc.jam and +# msvc.jam +type.register('RCC', ['rcc']) + +generators.register_standard("rcc.resource-compile", ["RCC"], ["OBJ"]) + +get_manager().engine().register_action( + "rcc.resource-compile", + '@($(STDOUT):E=rc-object) > "$(<)"') +""") + t.write("jamfile.jam", """ obj r : r.rcc ; """) From bcff7f4c9faf86601557444c4311c51374f1b1ec Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 12:45:48 +0000 Subject: [PATCH 103/165] Do not make source-location attribute always absolute. Also, adjust reporting and expectations for metatarget reference recursion. [SVN r64636] --- v2/build/project.py | 6 +++--- v2/build/targets.py | 6 ++---- v2/test/loop.py | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 52268c693..4daae3be8 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -306,10 +306,10 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" is_jamroot = True jamfile_to_load = jamfile_to_load[0] - - # The module of the jamfile. - dir = os.path.realpath(os.path.dirname(jamfile_to_load)) + dir = os.path.dirname(jamfile_to_load) + if not dir: + dir = "." # Initialize the jamfile module before loading. # self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load)) diff --git a/v2/build/targets.py b/v2/build/targets.py index f439dd1a5..5b4465c85 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -197,12 +197,10 @@ class TargetRegistry: """ if self.targets_being_built_.has_key(id(main_target_instance)): names = [] - for t in self.targets_being_built_.values(): + for t in self.targets_being_built_.values() + [main_target_instance]: names.append (t.full_name()) - get_manager().errors()( - "Recursion in main target references\n" - "the following target are being built currently: '%s'" % names) + get_manager().errors()("Recursion in main target references\n") self.targets_being_built_[id(main_target_instance)] = main_target_instance diff --git a/v2/test/loop.py b/v2/test/loop.py index 4455b9789..f01b95973 100644 --- a/v2/test/loop.py +++ b/v2/test/loop.py @@ -21,6 +21,5 @@ t.write("l.cpp", "") t.run_build_system("--no-error-backtrace", status=1) t.fail_test(string.find(t.stdout(), "error: Recursion in main target references") == -1) -t.fail_test(string.find(t.stdout(), "./main ./l ./main") == -1) t.cleanup() From c2289d37351650a1270f2620b4c37586363da1b2 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 12:56:05 +0000 Subject: [PATCH 104/165] Adjust one place after resolve_references move. [SVN r64637] --- v2/build/targets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/build/targets.py b/v2/build/targets.py index 5b4465c85..366c9c2c6 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -869,7 +869,7 @@ class BasicTarget (AbstractTarget): if self.source_targets_ == None: self.source_targets_ = [] for s in self.sources_: - self.source_targets_.append(self.resolve_reference(s, self.project_)[0]) + self.source_targets_.append(resolve_reference(s, self.project_)[0]) return self.source_targets_ From f40b0c9002e19e3c28744d9a7b3d091617faf899 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 13:02:27 +0000 Subject: [PATCH 105/165] Preserve current project across 'using' statements. [SVN r64638] --- v2/build/project.py | 9 ++++++--- v2/test/wrong_project.py | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 4daae3be8..cb9132e9f 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -1053,9 +1053,8 @@ attribute is allowed only for top-level 'project' invocations""") # will expect the module to be found even though # the directory is not in BOOST_BUILD_PATH. # So temporary change the search path. - jamfile_module = self.registry.current().project_module() - attributes = self.registry.attributes(jamfile_module) - location = attributes.get("location") + current = self.registry.current() + location = current.get('location') m = self.registry.load_module(toolset[0], [location]) if not m.__dict__.has_key("init"): @@ -1063,6 +1062,10 @@ attribute is allowed only for top-level 'project' invocations""") "Tool module '%s' does not define the 'init' method" % toolset[0]) m.init(*args) + # The above might have clobbered .current-project. Restore the correct + # value. + self.registry.set_current(current) + def import_(self, name, names_to_import=None, local_names=None): name = name[0] diff --git a/v2/test/wrong_project.py b/v2/test/wrong_project.py index 58d00d02e..88315d64e 100644 --- a/v2/test/wrong_project.py +++ b/v2/test/wrong_project.py @@ -26,6 +26,15 @@ project.initialize $(__name__) ; rule init ( ) { } """) +t.write("some_tool.py", """ +from b2.manager import get_manager + +get_manager().projects().initialize(__name__) + +def init(): + pass +""") + t.run_build_system() t.expect_addition("bin/$toolset/debug/a.exe") From f93710d36221d800dbb6e221baac63759c17dee4 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 13:04:21 +0000 Subject: [PATCH 106/165] Fix test/using.py. [SVN r64639] --- v2/test/using.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/v2/test/using.py b/v2/test/using.py index 4e47f5f7f..452e7363b 100644 --- a/v2/test/using.py +++ b/v2/test/using.py @@ -23,6 +23,15 @@ project.initialize $(__name__) ; rule init ( ) { } """) +t.write("some_tool.py", """ +from b2.manager import get_manager + +get_manager().projects().initialize(__name__) + +def init(): + pass +""") + t.write("sub/jamfile.jam", """ exe a : a.cpp ; """) From 921305354738b220fa6616252dca435f85d5a046 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 13:26:53 +0000 Subject: [PATCH 107/165] Make the 'cached' decorator work on methods. [SVN r64640] --- v2/build/property_set.py | 4 +++- v2/util/__init__.py | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/v2/build/property_set.py b/v2/build/property_set.py index a8f8597ea..19d2c27df 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -12,9 +12,11 @@ import b2.build.feature from b2.exceptions import * from b2.util.sequence import unique from b2.util.set import difference +from b2.util import cached from b2.manager import get_manager + def reset (): """ Clear the module state. This is mainly for testing purposes. """ @@ -427,7 +429,7 @@ class PropertySet: return self.feature_map_.get(feature, []) - # FIXME: make this cached + @cached def get_properties(self, feature): """Returns all contained properties associated with 'feature'""" diff --git a/v2/util/__init__.py b/v2/util/__init__.py index 99d34cdd0..a53988f3b 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -30,7 +30,10 @@ class cached(object): except KeyError: v = self.function(*args) self.cache[args] = v - return v + return v + + def __get__(self, instance, type): + return types.MethodType(self, instance, type) def unquote(s): if s and s[0] == '"' and s[-1] == '"': From befe7552b71579c54faf5f51dfeef8033372ad7a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 6 Aug 2010 15:37:13 +0000 Subject: [PATCH 108/165] Port tools/package.py. Fix various bugs. [SVN r64643] --- v2/build/feature.py | 13 ++-- v2/build/targets.py | 2 +- v2/tools/package.py | 168 ++++++++++++++++++++++++++++++++++++++++++++ v2/tools/stage.py | 3 +- v2/util/option.py | 2 +- 5 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 v2/tools/package.py diff --git a/v2/build/feature.py b/v2/build/feature.py index 40a624d02..315a18e94 100644 --- a/v2/build/feature.py +++ b/v2/build/feature.py @@ -27,6 +27,7 @@ class Feature(object): def __init__(self, name, values, attributes): self._name = name self._values = values + self._default = None self._attributes = 0 for a in attributes: self._attributes = self._attributes | Feature._attribute_name_to_integer[a] @@ -68,6 +69,7 @@ class Feature(object): Value may be None if this subfeature is not specific to any value of the parent feature. """ + return self._parent def set_parent(self, feature, value): self._parent = (feature, value) @@ -512,9 +514,9 @@ def subfeature (feature_name, value_string, subfeature, subvalues, attributes = # First declare the subfeature as a feature in its own right f = feature (feature_name + '-' + subfeature_name, subvalues, attributes + ['subfeature']) f.set_parent(parent_feature, value_string) - - parent_feature.add_subfeature(f) + parent_feature.add_subfeature(f) + # Now make sure the subfeature values are known. extend_subfeature (feature_name, value_string, subfeature, subvalues) @@ -761,7 +763,7 @@ def minimize (properties): if subproperties: # reconstitute the joined property name subproperties.sort () - joined = Property(p.feature(), p.value() + '-' + '-'.join ([sp.value() for sp in subproperties])) + joined = b2.build.property.Property(p.feature(), p.value() + '-' + '-'.join ([sp.value() for sp in subproperties])) result.append(joined) properties = b2.util.set.difference(properties[1:], subproperties) @@ -843,8 +845,9 @@ def compress_subproperties (properties): matched_subs.update(subs) subvalues = '-'.join (sub.value() for sub in subs) - result.append(Property(p.feature(), p.value + '-' + subvalues, - p.condition())) + result.append(b2.build.property.Property( + p.feature(), p.value() + '-' + subvalues, + p.condition())) else: result.append(p) diff --git a/v2/build/targets.py b/v2/build/targets.py index 366c9c2c6..a9c0bca50 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -831,7 +831,7 @@ class BasicTarget (AbstractTarget): for s in sources: if get_grist (s): - raise InvalidSource ("property '%s' found in the 'sources' parameter for '%s'" (s, name)) + raise InvalidSource ("property '%s' found in the 'sources' parameter for '%s'" % (s, name)) self.sources_ = sources diff --git a/v2/tools/package.py b/v2/tools/package.py new file mode 100644 index 000000000..5b267a25c --- /dev/null +++ b/v2/tools/package.py @@ -0,0 +1,168 @@ +# Status: ported +# Base revision: 64488 +# +# Copyright (c) 2005, 2010 Vladimir Prus. +# Copyright 2006 Rene Rivera. +# +# Use, modification and distribution is subject to the Boost Software +# License Version 1.0. (See accompanying file LICENSE_1_0.txt or +# http://www.boost.org/LICENSE_1_0.txt) + +# Provides mechanism for installing whole packages into a specific directory +# structure. This is opposed to the 'install' rule, that installs a number of +# targets to a single directory, and does not care about directory structure at +# all. + +# Example usage: +# +# package.install boost : +# : +# : +# : +# ; +# +# This will install binaries, libraries and headers to the 'proper' location, +# given by command line options --prefix, --exec-prefix, --bindir, --libdir and +# --includedir. +# +# The rule is just a convenient wrapper, avoiding the need to define several +# 'install' targets. +# +# The only install-related feature is . It will apply to +# headers only and if present, paths of headers relatively to source root will +# be retained after installing. If it is not specified, then "." is assumed, so +# relative paths in headers are always preserved. + +import b2.build.feature as feature +import b2.build.property as property +import b2.util.option as option +import b2.tools.stage as stage + +from b2.build.alias import alias + +from b2.manager import get_manager + +from b2.util import bjam_signature +from b2.util.utility import ungrist + + +import os + +feature.feature("install-default-prefix", [], ["free", "incidental"]) + +@bjam_signature((["name", "package_name", "?"], ["requirements", "*"], + ["binaries", "*"], ["libraries", "*"], ["headers", "*"])) +def install(name, package_name=None, requirements=[], binaries=[], libraries=[], headers=[]): + + requirements = requirements[:] + binaries = binaries[:] + libraries + + if not package_name: + package_name = name + + if option.get("prefix"): + # If --prefix is explicitly specified on the command line, + # then we need wipe away any settings of libdir/includir that + # is specified via options in config files. + option.set("bindir", None) + option.set("libdir", None) + option.set("includedir", None) + + # If is not specified, all headers are installed to + # prefix/include, no matter what their relative path is. Sometimes that is + # what is needed. + install_source_root = property.select('install-source-root', requirements) + if install_source_root: + requirements = property.change(requirements, 'install-source-root', None) + + install_header_subdir = property.select('install-header-subdir', requirements) + if install_header_subdir: + install_header_subdir = ungrist(install_header_subdir[0]) + requirements = property.change(requirements, 'install-header-subdir', None) + + # First, figure out all locations. Use the default if no prefix option + # given. + prefix = get_prefix(name, requirements) + + # Architecture dependent files. + exec_locate = option.get("exec-prefix", prefix) + + # Binaries. + bin_locate = option.get("bindir", os.path.join(prefix, "bin")) + + # Object code libraries. + lib_locate = option.get("libdir", os.path.join(prefix, "lib")) + + # Source header files. + include_locate = option.get("includedir", os.path.join(prefix, "include")) + + stage.install(name + "-bin", binaries, requirements + ["" + bin_locate]) + + alias(name + "-lib", [name + "-lib-shared", name + "-lib-static"]) + + # Since the install location of shared libraries differs on universe + # and cygwin, use target alternatives to make different targets. + # We should have used indirection conditioanl requirements, but it's + # awkward to pass bin-locate and lib-locate from there to another rule. + alias(name + "-lib-shared", [name + "-lib-shared-universe"]) + alias(name + "-lib-shared", [name + "-lib-shared-cygwin"], ["cygwin"]) + + # For shared libraries, we install both explicitly specified one and the + # shared libraries that the installed executables depend on. + stage.install(name + "-lib-shared-universe", binaries, libraries, + requirements + ["" + lib_locate, "on", + "SHARED_LIB"]) + stage.install(name + "-lib-shared-cygwin", binaries, libraries, + requirements + ["" + bin_locate, "on", + "SHARED_LIB"]) + + # For static libraries, we do not care about executable dependencies, since + # static libraries are already incorporated into them. + stage.install(name + "-lib-static", libraries, requirements + + ["" + lib_locate, "on", "STATIC_LIB"]) + stage.install(name + "-headers", headers, requirements \ + + ["" + os.path.join(include_locate, s) for s in install_header_subdir] + + install_source_root) + + alias(name, [name + "-bin", name + "-lib", name + "-headers"]) + + pt = get_manager().projects().current() + + for subname in ["bin", "lib", "headers", "lib-shared", "lib-static", "lib-shared-universe", "lib-shared-cygwin"]: + pt.mark_target_as_explicit(name + "-" + subname) + +@bjam_signature((["target_name"], ["package_name"], ["data", "*"], ["requirements", "*"])) +def install_data(target_name, package_name, data, requirements): + if not package_name: + package_name = target_name + + if option.get("prefix"): + # If --prefix is explicitly specified on the command line, + # then we need wipe away any settings of datarootdir + option.set("datarootdir", None) + + prefix = get_prefix(package_name, requirements) + datadir = option.get("datarootdir", os.path.join(prefix, "share")) + + stage.install(target_name, data, + requirements + ["" + os.path.join(datadir, package_name)]) + + get_manager().projects().current().mark_target_as_explicit(target_name) + +def get_prefix(package_name, requirements): + + specified = property.select("install-default-prefix", requirements) + if specified: + specified = ungrist(specified[0]) + prefix = option.get("prefix", specified) + requirements = property.change(requirements, "install-default-prefix", None) + # Or some likely defaults if neither is given. + if not prefix: + if os.name == "nt": + prefix = "C:\\" + package_name + elif os.name == "posix": + prefix = "/usr/local" + + return prefix + diff --git a/v2/tools/stage.py b/v2/tools/stage.py index 82b253571..25eccbe51 100644 --- a/v2/tools/stage.py +++ b/v2/tools/stage.py @@ -322,8 +322,9 @@ generators.register(InstalledSharedLibGenerator()) # @bjam_signature((["name"], ["sources", "*"], ["requirements", "*"], ["default_build", "*"], ["usage_requirements", "*"])) -def install(name, sources, requirements, default_build, usage_requirements): +def install(name, sources, requirements=[], default_build=[], usage_requirements=[]): + requirements = requirements[:] # Unless the user has explicitly asked us to hardcode dll paths, add # false in requirements, to override default value. if not 'true' in requirements: diff --git a/v2/util/option.py b/v2/util/option.py index 3778183ac..47d6abdff 100644 --- a/v2/util/option.py +++ b/v2/util/option.py @@ -29,7 +29,7 @@ def get(name, default_value=None, implied_value=None): m = b2.util.regex.transform(sys.argv, "--(" + re.escape(name) + ")") if m and implied_value: return implied_value - elif options.has_key(name): + elif options.has_key(name) and options[name] != None: return options[name] else: return default_value From 8ae8c29375d208bff7d1d942ac01474862eab0b0 Mon Sep 17 00:00:00 2001 From: "K. Noel Belcourt" Date: Fri, 6 Aug 2010 18:44:15 +0000 Subject: [PATCH 109/165] Add bjam build for intel-darwin (Intel on Darwin). [SVN r64647] --- v2/engine/src/build.jam | 7 +++++++ v2/engine/src/build.sh | 8 ++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/v2/engine/src/build.jam b/v2/engine/src/build.jam index 432197cc2..d53b4928f 100644 --- a/v2/engine/src/build.jam +++ b/v2/engine/src/build.jam @@ -215,6 +215,13 @@ toolset gcc-nocygwin gcc : "-o " : -D [ opt --debug : -s -O3 -fno-inline -pg ] -I$(--python-include) -I$(--extra-include) : -L$(--python-lib[1]) -l$(--python-lib[2]) ; +## Intel C/C++ for Darwin +toolset intel-darwin icc : "-o " : -D + : + [ opt --release : -O3 ] + [ opt --debug : -g -O0 -p ] + -I$(--python-include) -I$(--extra-include) + : -L$(--python-lib[1]) -l$(--python-lib[2]) ; ## Intel C/C++ for Linux toolset intel-linux icc : "-o " : -D : diff --git a/v2/engine/src/build.sh b/v2/engine/src/build.sh index ce97ff940..3f23fc683 100755 --- a/v2/engine/src/build.sh +++ b/v2/engine/src/build.sh @@ -29,8 +29,8 @@ error_exit () echo "### ./build.sh gcc" echo "###" echo "### Toolsets supported by this script are:" - echo "### acc, como, darwin, gcc, intel-linux, kcc, kylix, mipspro," - echo "### mingw(msys), pathscale, pgi, qcc, sun, sunpro, tru64cxx, vacpp" + echo "### acc, como, darwin, gcc, intel-darwin, intel-linux, kcc, kylix," + echo "### mipspro, mingw(msys), pathscale, pgi, qcc, sun, sunpro, tru64cxx, vacpp" echo "###" echo "### A special toolset; cc, is available which is used as a fallback" echo "### when a more specific toolset is not found and the cc command is" @@ -136,6 +136,10 @@ case $BOOST_JAM_TOOLSET in BOOST_JAM_CC=cc ;; + intel-darwin) + BOOST_JAM_CC=icc + ;; + intel-linux) if test -r /opt/intel/cc/9.0/bin/iccvars.sh ; then BOOST_JAM_TOOLSET_ROOT=/opt/intel/cc/9.0/ From a273e0d03e415aa7c64326a3236e78c812e04753 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 9 Aug 2010 08:35:02 +0000 Subject: [PATCH 110/165] Make 'mark-target-as-explicit' accept multiple target names. [SVN r64689] --- v2/build/project.py | 8 ++------ v2/build/targets.jam | 4 ++-- v2/build/targets.py | 6 +++--- v2/tools/package.py | 4 ++-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index cb9132e9f..1739d787a 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -1016,14 +1016,10 @@ attribute is allowed only for top-level 'project' invocations""") attributes.set("projects-to-build", now + dir, exact=True) def explicit(self, target_names): - t = self.registry.current() - for n in target_names: - t.mark_target_as_explicit(n) + self.registry.current().mark_targets_as_explicit(target_names) def always(self, target_names): - p = self.registry.current() - for n in target_names: - p.mark_target_as_always(n) + self.registry.current().mark_targets_as_alays(target_names) def glob(self, wildcards, excludes=None): return self.registry.glob_internal(self.registry.current(), diff --git a/v2/build/targets.jam b/v2/build/targets.jam index f988e691b..a70532ce7 100644 --- a/v2/build/targets.jam +++ b/v2/build/targets.jam @@ -297,14 +297,14 @@ class project-target : abstract-target # Add 'target' to the list of targets in this project that should be build # only by explicit request # - rule mark-target-as-explicit ( target-name ) + rule mark-target-as-explicit ( target-name * ) { # Record the name of the target, not instance, since this rule is called # before main target instances are created. self.explicit-targets += $(target-name) ; } - rule mark-target-as-always ( target-name ) + rule mark-target-as-always ( target-name * ) { # Record the name of the target, not instance, since this rule is called # before main target instances are created. diff --git a/v2/build/targets.py b/v2/build/targets.py index a9c0bca50..87f96a4af 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -131,7 +131,7 @@ class TargetRegistry: # Inline targets are not built by default. p = t.project() - p.mark_target_as_explicit(name) + p.mark_targets_as_explicit([name]) result.append(name) else: @@ -441,7 +441,7 @@ class ProjectTarget (AbstractTarget): return result - def mark_target_as_explicit (self, target_name): + def mark_targets_as_explicit (self, target_names): """Add 'target' to the list of targets in this project that should be build only by explicit request.""" @@ -449,7 +449,7 @@ class ProjectTarget (AbstractTarget): # rule is called before main target instaces are created. self.explicit_targets_.add(target_name) - def mark_target_as_always(self, target_name): + def mark_targets_as_always(self, target_names): self.always_targets_.add(target_name) def add_alternative (self, target_instance): diff --git a/v2/tools/package.py b/v2/tools/package.py index 5b267a25c..676a4d746 100644 --- a/v2/tools/package.py +++ b/v2/tools/package.py @@ -130,7 +130,7 @@ def install(name, package_name=None, requirements=[], binaries=[], libraries=[], pt = get_manager().projects().current() for subname in ["bin", "lib", "headers", "lib-shared", "lib-static", "lib-shared-universe", "lib-shared-cygwin"]: - pt.mark_target_as_explicit(name + "-" + subname) + pt.mark_targets_as_explicit([name + "-" + subname]) @bjam_signature((["target_name"], ["package_name"], ["data", "*"], ["requirements", "*"])) def install_data(target_name, package_name, data, requirements): @@ -148,7 +148,7 @@ def install_data(target_name, package_name, data, requirements): stage.install(target_name, data, requirements + ["" + os.path.join(datadir, package_name)]) - get_manager().projects().current().mark_target_as_explicit(target_name) + get_manager().projects().current().mark_targets_as_explicit([target_name]) def get_prefix(package_name, requirements): From c49d198fd374dbb4f662655cbb1de61e2d962d08 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 9 Aug 2010 10:30:54 +0000 Subject: [PATCH 111/165] Improve python-to-jam-to-python tunnelling of values, and 'generate' metatarget. [SVN r64691] --- v2/build/engine.py | 14 -------------- v2/build/project.py | 17 ++++++----------- v2/build/property.py | 4 ++-- v2/build/targets.py | 4 ++-- v2/build/toolset.py | 4 ++-- v2/example/generate/jamroot.jam | 2 +- v2/util/__init__.py | 20 ++++++++++++++++++-- 7 files changed, 31 insertions(+), 34 deletions(-) diff --git a/v2/build/engine.py b/v2/build/engine.py index 23fd6e58c..be9736e06 100644 --- a/v2/build/engine.py +++ b/v2/build/engine.py @@ -12,8 +12,6 @@ import re import b2.build.property_set as property_set import b2.util -_indirect_rule = re.compile("^([^%]*)%([^%]+)$") - class BjamAction: """Class representing bjam action defined from Python.""" @@ -138,18 +136,6 @@ class Engine: self.actions[action_name] = BjamAction(action_name, function) - def qualify_bjam_action(self, action_name, context_module): - - if _indirect_rule.match(action_name): - # Rule is already in indirect format - return action_name - else: - ix = action_name.find('.') - if ix != -1 and action_name[:ix] == context_module: - return context_module + '%' + action_name[ix+1:] - - return context_module + '%' + action_name - def register_bjam_action (self, action_name, function=None): """Informs self that 'action_name' is declared in bjam. diff --git a/v2/build/project.py b/v2/build/project.py index 1739d787a..8199579cf 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -53,6 +53,8 @@ import imp import traceback import b2.util.option as option +from b2.util import record_jam_to_value_mapping, qualify_jam_action + class ProjectRegistry: def __init__(self, manager, global_build_dir): @@ -847,7 +849,6 @@ class ProjectRules: if x not in ["__init__", "init_project", "add_rule", "error_reporting_wrapper", "add_rule_for_type", "reverse"]] self.all_names_ = [x for x in self.local_names] - self.reverse = {} def _import_rule(self, bjam_module, name, callable): if hasattr(callable, "bjam_signature"): @@ -1080,8 +1081,10 @@ attribute is allowed only for top-level 'project' invocations""") v = m.__dict__[f] f = f.replace("_", "-") if callable(v): - self._import_rule(jamfile_module, name + "." + f, v) - self.reverse.setdefault(jamfile_module, {})[name + "." + f] = v + qn = name + "." + f + self._import_rule(jamfile_module, qn, v) + record_jam_to_value_mapping(qualify_jam_action(qn, jamfile_module), v) + if names_to_import: if not local_names: @@ -1111,14 +1114,6 @@ attribute is allowed only for top-level 'project' invocations""") else: return [c + ":" + r for r in requirements] - def reverse_lookup(self, jamfile_module, name_in_jamfile_modue): - """Return callable that we've previously imported to jam.""" - - if self.reverse.has_key(jamfile_module): - return self.reverse[jamfile_module].get(name_in_jamfile_modue, None) - - return None - def option(self, name, value): name = name[0] if not name in ["site-config", "user-config", "project-config"]: diff --git a/v2/build/property.py b/v2/build/property.py index fece8c6d8..c4b13dbcb 100644 --- a/v2/build/property.py +++ b/v2/build/property.py @@ -10,7 +10,7 @@ import re from b2.util.utility import * from b2.build import feature -from b2.util import sequence +from b2.util import sequence, qualify_jam_action import b2.util.set from b2.manager import get_manager @@ -215,7 +215,7 @@ def translate_indirect(properties, context_module): result = [] for p in properties: if p.value()[0] == '@': - q = get_manager().engine().qualify_bjam_action(p.value()[1:], context_module) + q = qualify_jam_action(p.value()[1:], context_module) get_manager().engine().register_bjam_action(q) result.append(Property(p.feature(), '@' + q, p.condition())) else: diff --git a/v2/build/targets.py b/v2/build/targets.py index 87f96a4af..716cc2645 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -447,10 +447,10 @@ class ProjectTarget (AbstractTarget): # Record the name of the target, not instance, since this # rule is called before main target instaces are created. - self.explicit_targets_.add(target_name) + self.explicit_targets_.update(target_names) def mark_targets_as_always(self, target_names): - self.always_targets_.add(target_name) + self.always_targets_.update(target_names) def add_alternative (self, target_instance): """ Add new target alternative. diff --git a/v2/build/toolset.py b/v2/build/toolset.py index c5e1fb38f..b42679878 100644 --- a/v2/build/toolset.py +++ b/v2/build/toolset.py @@ -12,7 +12,7 @@ import feature, property, generators, property_set import b2.util.set -from b2.util import cached +from b2.util import cached, qualify_jam_action from b2.util.utility import * from b2.util import bjam_signature from b2.manager import get_manager @@ -122,7 +122,7 @@ def flags(rule_or_module, variable_name, condition, values = []): # Jamfile module (this will be considered as rule), but who cares? # Probably, 'flags' rule should be split into 'flags' and # 'flags-on-module'. - rule_or_module = get_manager().engine().qualify_bjam_action(rule_or_module, caller) + rule_or_module = qualify_jam_action(rule_or_module, caller) else: # FIXME: revive checking that we don't set flags for a different # module unintentionally diff --git a/v2/example/generate/jamroot.jam b/v2/example/generate/jamroot.jam index 07b8623b4..c48f2207b 100644 --- a/v2/example/generate/jamroot.jam +++ b/v2/example/generate/jamroot.jam @@ -6,4 +6,4 @@ import generate ; import gen ; -generate a2 : a.cpp : @gen.generate_example ; +generate a2 : a.cpp : @gen.generate-example ; diff --git a/v2/util/__init__.py b/v2/util/__init__.py index a53988f3b..f0fb48eb5 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -43,6 +43,19 @@ def unquote(s): _extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)") +def qualify_jam_action(action_name, context_module): + + if _extract_jamfile_and_rule.match(action_name): + # Rule is already in indirect format + return action_name + else: + ix = action_name.find('.') + if ix != -1 and action_name[:ix] == context_module: + return context_module + '%' + action_name[ix+1:] + + return context_module + '%' + action_name + + def set_jam_action(name, *args): m = _extract_jamfile_and_rule.match(name) @@ -102,10 +115,13 @@ def value_to_jam(value, methods=False): return exported_name +def record_jam_to_value_mapping(jam_value, python_value): + __jam_to_python[jam_value] = python_value + def jam_to_value_maybe(jam_value): - if type(jam_value) == type("") and jam_value.startswith("###"): - return __jam_to_python[jam_value] + if type(jam_value) == type(""): + return __jam_to_python.get(jam_value, jam_value) else: return jam_value From 32eec4e9a0e15ff9fa83ff5172adb4d417991c9f Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 9 Aug 2010 20:52:52 +0000 Subject: [PATCH 112/165] Fix python/jam translation some more. [SVN r64707] --- v2/util/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/v2/util/__init__.py b/v2/util/__init__.py index f0fb48eb5..f80fe70e9 100644 --- a/v2/util/__init__.py +++ b/v2/util/__init__.py @@ -44,8 +44,11 @@ def unquote(s): _extract_jamfile_and_rule = re.compile("(Jamfile<.*>)%(.*)") def qualify_jam_action(action_name, context_module): - - if _extract_jamfile_and_rule.match(action_name): + + if action_name.startswith("###"): + # Callable exported from Python. Don't touch + return action_name + elif _extract_jamfile_and_rule.match(action_name): # Rule is already in indirect format return action_name else: From bbb80ee03d5afac7d2ffdc03dace85a580d12765 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 9 Aug 2010 20:54:29 +0000 Subject: [PATCH 113/165] Port tools/message.jam. [SVN r64708] --- v2/tools/builtin.py | 1 + v2/tools/message.py | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 v2/tools/message.py diff --git a/v2/tools/builtin.py b/v2/tools/builtin.py index c0142db98..31a7bffee 100644 --- a/v2/tools/builtin.py +++ b/v2/tools/builtin.py @@ -715,3 +715,4 @@ get_manager().projects().add_rule("variant", variant) import stage import symlink +import message diff --git a/v2/tools/message.py b/v2/tools/message.py new file mode 100644 index 000000000..cc0b946ff --- /dev/null +++ b/v2/tools/message.py @@ -0,0 +1,46 @@ +# Status: ported. +# Base revision: 64488. +# +# Copyright 2008, 2010 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) + +# Defines main target type 'message', that prints a message when built for the +# first time. + +import b2.build.targets as targets +import b2.build.property_set as property_set + +from b2.manager import get_manager + +class MessageTargetClass(targets.BasicTarget): + + def __init__(self, name, project, *args): + + targets.BasicTarget.__init__(self, name, project, []) + self.args = args + self.built = False + + def construct(self, name, sources, ps): + + if not self.built: + for arg in self.args: + if type(arg) == type([]): + arg = " ".join(arg) + print arg + self.built = True + + return (property_set.empty(), []) + +def message(name, *args): + + if type(name) == type([]): + name = name[0] + + t = get_manager().targets() + + project = get_manager().projects().current() + + return t.main_target_alternative(MessageTargetClass(*((name, project) + args))) + +get_manager().projects().add_rule("message", message) From 92f894ac15b35307c5ca21b6901ad25d8934d659 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Fri, 13 Aug 2010 06:39:33 +0000 Subject: [PATCH 114/165] Update URL [SVN r64776] --- v2/user-config.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/user-config.jam b/v2/user-config.jam index 54718bb2e..f0c7acc33 100644 --- a/v2/user-config.jam +++ b/v2/user-config.jam @@ -8,7 +8,7 @@ # this file in place, or you can place it in a permanent location so that it # does not get overwritten should you get a new version of Boost.Build. See: # -# http://boost.org/boost-build2/doc/html/bbv2/reference.html#bbv2.reference.init +# http://www.boost.org/boost-build2/doc/html/bbv2/overview/configuration.html # # for documentation about possible permanent locations. From 7c716773931e95bbe965d0bcab97a0d013b75f99 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 17 Aug 2010 16:49:44 +0000 Subject: [PATCH 115/165] Supress -q for configuration checks. [SVN r64861] --- v2/engine/src/builtins.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/v2/engine/src/builtins.c b/v2/engine/src/builtins.c index 29c6d9fb2..b406dba69 100644 --- a/v2/engine/src/builtins.c +++ b/v2/engine/src/builtins.c @@ -1320,6 +1320,7 @@ LIST * builtin_update_now( PARSE * parse, FRAME * frame ) const char** targets2; int i; int original_noexec; + int original_quitquick; if (log) @@ -1336,6 +1337,8 @@ LIST * builtin_update_now( PARSE * parse, FRAME * frame ) { original_noexec = globs.noexec; globs.noexec = 0; + original_quitquick = globs.quitquick; + globs.quitquick = 0; } targets_count = list_length( targets ); @@ -1348,6 +1351,7 @@ LIST * builtin_update_now( PARSE * parse, FRAME * frame ) if (force) { globs.noexec = original_noexec; + globs.quitquick = original_quitquick; } if (log) From 4a99d65979c713183832728cdd9235fd9515518a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 18 Aug 2010 07:19:32 +0000 Subject: [PATCH 116/165] Fix typo. [SVN r64877] --- v2/tools/package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/v2/tools/package.py b/v2/tools/package.py index 676a4d746..aa081b4f4 100644 --- a/v2/tools/package.py +++ b/v2/tools/package.py @@ -110,10 +110,10 @@ def install(name, package_name=None, requirements=[], binaries=[], libraries=[], # For shared libraries, we install both explicitly specified one and the # shared libraries that the installed executables depend on. - stage.install(name + "-lib-shared-universe", binaries, libraries, + stage.install(name + "-lib-shared-universe", binaries + libraries, requirements + ["" + lib_locate, "on", "SHARED_LIB"]) - stage.install(name + "-lib-shared-cygwin", binaries, libraries, + stage.install(name + "-lib-shared-cygwin", binaries + libraries, requirements + ["" + bin_locate, "on", "SHARED_LIB"]) From f6917faf8aa4dbfbacb504cb8269bb8a40f62d8c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 18 Aug 2010 07:27:13 +0000 Subject: [PATCH 117/165] Unbreak processing of - requirements. [SVN r64878] --- v2/build/property_set.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/v2/build/property_set.py b/v2/build/property_set.py index 19d2c27df..f12eb90c1 100644 --- a/v2/build/property_set.py +++ b/v2/build/property_set.py @@ -107,21 +107,21 @@ def refine_from_user_input(parent_requirements, specification, jamfile_module, else: add_requirements.append(r) - if remove_requirements: - # Need to create property set, so that path features - # and indirect features are translated just like they - # are in project requirements. - ps = create_from_user_input(remove_requirements, - jamfile_module, location) - - parent_requirements = create(difference(parent_requirements.all(), - ps.all())) - specification = add_requirements - - requirements = create_from_user_input(specification, - jamfile_module, location) + if remove_requirements: + # Need to create property set, so that path features + # and indirect features are translated just like they + # are in project requirements. + ps = create_from_user_input(remove_requirements, + jamfile_module, location) - return parent_requirements.refine(requirements) + parent_requirements = create(difference(parent_requirements.all(), + ps.all())) + specification = add_requirements + + requirements = create_from_user_input(specification, + jamfile_module, location) + + return parent_requirements.refine(requirements) class PropertySet: """ Class for storing a set of properties. @@ -317,6 +317,8 @@ class PropertySet: return self.propagated_ps_ def add_defaults (self): + # FIXME: this caching is invalidated when new features + # are declare inside non-root Jamfiles. if not self.defaults_: expanded = feature.add_defaults(self.all_) self.defaults_ = create(expanded) From d8aba8b02b974ad80fbfa5db7152221c74caaad6 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 18 Aug 2010 07:35:53 +0000 Subject: [PATCH 118/165] Don't crash when inheriting more than one function from parent Jamfile. [SVN r64879] --- v2/kernel/bootstrap.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/kernel/bootstrap.jam b/v2/kernel/bootstrap.jam index c345ba705..89048af92 100644 --- a/v2/kernel/bootstrap.jam +++ b/v2/kernel/bootstrap.jam @@ -226,7 +226,7 @@ if ! $(dont-build) return [ on $(targets) return $($(variable)) ] ; } - rule import-rules-from-parent ( parent-module : this-module : user-rules ) + rule import-rules-from-parent ( parent-module : this-module : user-rules * ) { IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules) ; EXPORT $(this-module) : $(user-rules) ; From e3e0cb61ea7ba013a4e5b73e9e041f56304c297b Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 18 Aug 2010 07:38:43 +0000 Subject: [PATCH 119/165] Fix default build and other things. [SVN r64880] --- v2/build/alias.py | 6 ++---- v2/build/project.py | 4 ++-- v2/build/targets.py | 32 +++++++++++++++++++++++++------- v2/build/virtual_target.py | 2 +- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/v2/build/alias.py b/v2/build/alias.py index f83a25bef..575e53609 100755 --- a/v2/build/alias.py +++ b/v2/build/alias.py @@ -46,13 +46,11 @@ class AliasTarget(targets.BasicTarget): return base.add(subvariant.sources_usage_requirements()) @metatarget -def alias(name, sources, requirements=None, default_build=None, usage_requirements=None): +def alias(name, sources=[], requirements=[], default_build=[], usage_requirements=[]): + project = get_manager().projects().current() targets = get_manager().targets() - if default_build: - default_build = default_build[0] - targets.main_target_alternative(AliasTarget( name, project, targets.main_target_sources(sources, name, no_renaming=True), diff --git a/v2/build/project.py b/v2/build/project.py index 8199579cf..f08e918ae 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -421,7 +421,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) attributes.set("requirements", property_set.empty(), exact=True) attributes.set("usage-requirements", property_set.empty(), exact=True) - attributes.set("default-build", [], exact=True) + attributes.set("default-build", property_set.empty(), exact=True) attributes.set("projects-to-build", [], exact=True) attributes.set("project-root", None, exact=True) attributes.set("build-dir", None, exact=True) @@ -860,7 +860,7 @@ class ProjectRules: def add_rule_for_type(self, type): rule_name = type.lower().replace("_", "-") - def xpto (name, sources = [], requirements = [], default_build = None, usage_requirements = []): + def xpto (name, sources = [], requirements = [], default_build = [], usage_requirements = []): return self.manager_.targets().create_typed_target( type, self.registry.current(), name[0], sources, requirements, default_build, usage_requirements) diff --git a/v2/build/targets.py b/v2/build/targets.py index 716cc2645..a35612cea 100644 --- a/v2/build/targets.py +++ b/v2/build/targets.py @@ -185,12 +185,9 @@ class TargetRegistry: project: Project where the main target is to be declared """ if specification: - result = specification - + return property_set.create_with_validation(specification) else: - result = project.get ('default-build') - - return property_set.create_with_validation (result) + return project.get ('default-build') def start_building (self, main_target_instance): """ Helper rules to detect cycles in main target references. @@ -663,6 +660,9 @@ class MainTarget (AbstractTarget): if len (self.alternatives_) == 1: return self.alternatives_ [0] + if debug: + print "Property set for selection:", property_set + for v in self.alternatives_: properties = v.match (property_set, debug) @@ -853,7 +853,12 @@ class BasicTarget (AbstractTarget): # A cache for build requests self.request_cache = {} - self.user_context_ = self.manager_.errors().capture_user_context() + # Result of 'capture_user_context' has everything. For example, if this + # target is declare as result of loading Jamfile which was loaded when + # building target B which was requested from A, then we'll have A, B and + # Jamroot location in context. We only care about Jamroot location, most + # of the times. + self.user_context_ = self.manager_.errors().capture_user_context()[-1:] self.always_ = False @@ -1030,7 +1035,7 @@ class BasicTarget (AbstractTarget): condition = b2.util.set.difference (bcondition, ccondition) if debug: - print " next alternative: required properties:", str(condition) + print " next alternative: required properties:", [str(p) for p in condition] if b2.util.set.contains (condition, property_set.all()): @@ -1360,7 +1365,20 @@ def create_typed_metatarget(name, type, sources, requirements, default_build, us t.main_target_requirements(requirements, project), t.main_target_default_build(default_build, project), t.main_target_usage_requirements(usage_requirements, project))) + + +def create_metatarget(klass, name, sources, requirements=[], default_build=[], usage_requirements=[]): + from b2.manager import get_manager + t = get_manager().targets() + project = get_manager().projects().current() + + return t.main_target_alternative( + klass(name, project, + t.main_target_sources(sources, name), + t.main_target_requirements(requirements, project), + t.main_target_default_build(default_build, project), + t.main_target_usage_requirements(usage_requirements, project))) def metatarget_function_for_class(class_): diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index 6d9c65ebf..f688130ab 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -535,7 +535,7 @@ class AbstractFileTarget (VirtualTarget): if tag: if len(tag) > 1: - self.manager_.errors()( + get_manager().errors()( """@rulename is present but is not the only feature""") tag = tag[0] From 256491c938b300af78b470fd010e890805ba56e2 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 18 Aug 2010 07:40:08 +0000 Subject: [PATCH 120/165] Stub port of util/indirect.jam [SVN r64881] --- v2/util/indirect.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 v2/util/indirect.py diff --git a/v2/util/indirect.py b/v2/util/indirect.py new file mode 100644 index 000000000..78fa89946 --- /dev/null +++ b/v2/util/indirect.py @@ -0,0 +1,15 @@ +# Status: minimally ported. This module is not supposed to be used much +# with Boost.Build/Python. +# +# Copyright 2003 Dave Abrahams +# Copyright 2003 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +from b2.util import call_jam_function, bjam_signature + +def call(*args): + a1 = args[0] + name = a1[0] + a1tail = a1[1:] + call_jam_function(name, *((a1tail,) + args[1:])) From dce6b9b2641c550bfde32633b0c03fd3033c937c Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 18 Aug 2010 07:52:48 +0000 Subject: [PATCH 121/165] Fix a bug with -jN and actions that produce multiple targets. [SVN r64882] --- v2/build/virtual-target.jam | 15 ++++++++++++++- v2/build/virtual_target.py | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/v2/build/virtual-target.jam b/v2/build/virtual-target.jam index 87661adac..2e8446bcc 100644 --- a/v2/build/virtual-target.jam +++ b/v2/build/virtual-target.jam @@ -760,7 +760,20 @@ class action DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ; - + + # This works around a bug with -j and actions that + # produce multiple target, where: + # - dependency on the first output is found, and + # the action is started + # - dependency on the second output is found, and + # bjam noticed that command is already running + # - instead of waiting for the command, dependents + # of the second targets are immediately updated. + if $(actual-targets[2]) + { + INCLUDES $(actual-targets) : $(actual-targets) ; + } + # Action name can include additional argument to rule, which should # not be passed to 'set-target-variables' toolset.set-target-variables diff --git a/v2/build/virtual_target.py b/v2/build/virtual_target.py index f688130ab..51dff0374 100644 --- a/v2/build/virtual_target.py +++ b/v2/build/virtual_target.py @@ -797,6 +797,17 @@ class Action: self.engine_.add_dependency (actual_targets, self.actual_sources_ + self.dependency_only_sources_) + # This works around a bug with -j and actions that + # produce multiple target, where: + # - dependency on the first output is found, and + # the action is started + # - dependency on the second output is found, and + # bjam noticed that command is already running + # - instead of waiting for the command, dependents + # of the second targets are immediately updated. + if len(actual_targets) > 1: + bjam.call("INCLUDES", actual_targets, actual_targets) + # FIXME: check the comment below. Was self.action_name_ [1] # Action name can include additional argument to rule, which should not # be passed to 'set-target-variables' From f1a0a851447fbf111ca999906af269a99a422162 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 19 Aug 2010 07:47:23 +0000 Subject: [PATCH 122/165] Handle conditional requirements in check-target-builds. [SVN r64911] --- v2/build/configure.jam | 11 +++++++---- v2/build/configure.py | 20 ++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/v2/build/configure.jam b/v2/build/configure.jam index 474ff86fe..3edf98c89 100644 --- a/v2/build/configure.jam +++ b/v2/build/configure.jam @@ -191,18 +191,21 @@ class check-target-builds-worker { # FIXME: this should not be hardcoded. Other checks might # want to consider different set of features as relevant. - local toolset = [ property.select : $(properties) ] ; - local ps = [ property-set.create $(toolset) ] ; + local relevant = [ property.select + : $(properties) ] ; + local ps = [ property-set.create $(relevant) ] ; local t = [ targets.current ] ; local p = [ $(t).project ] ; + local choosen ; if [ configure.builds $(self.target) : $(p) : $(ps) : "$(self.target) builds" ] { - return $(self.true-properties) ; + choosen = $(self.true-properties) ; } else { - return $(self.false-properties) ; + choosen = $(self.false-properties) ; } + return [ property.evaluate-conditionals-in-context $(choosen) : $(properties) ] ; } } diff --git a/v2/build/configure.py b/v2/build/configure.py index 34bc9acd3..2c3e0534e 100644 --- a/v2/build/configure.py +++ b/v2/build/configure.py @@ -130,21 +130,25 @@ class CheckTargetBuildsWorker: def __init__(self, target, true_properties, false_properties): self.target = target - self.true_properties = property.create_from_strings(true_properties) - self.false_properties = property.create_from_strings(false_properties) + self.true_properties = property.create_from_strings(true_properties, True) + self.false_properties = property.create_from_strings(false_properties, True) def check(self, ps): # FIXME: this should not be hardcoded. Other checks might # want to consider different set of features as relevant. - toolset = ps.get_properties('toolset')[0] - ps = property_set.create([toolset]) + relevant = ps.get_properties('target-os') + \ + ps.get_properties("toolset") + \ + ps.get_properties("address-model") + \ + ps.get_properties("architecture") + rps = property_set.create(relevant) t = get_manager().targets().current() - p = t.project() - if builds(self.target, p, ps, "%s builds" % self.target): - return self.true_properties + p = t.project() + if builds(self.target, p, rps, "%s builds" % self.target): + choosen = self.true_properties else: - return self.false_properties + choosen = self.false_properties + return property.evaluate_conditionals_in_context(choosen, ps) @bjam_signature((["target"], ["true_properties", "*"], ["false_properties", "*"])) def check_target_builds(target, true_properties, false_properties): From 262c4abba6873ddcf35ca4a15e837419c3bf69c6 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 19 Aug 2010 07:50:50 +0000 Subject: [PATCH 123/165] Allow to customize the 'mt' tool. Patch from Victor Gaydov. [SVN r64912] --- v2/tools/msvc.jam | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/v2/tools/msvc.jam b/v2/tools/msvc.jam index 6bb0d6ff8..a7731cb54 100644 --- a/v2/tools/msvc.jam +++ b/v2/tools/msvc.jam @@ -905,8 +905,9 @@ local rule configure-really ( version ? : options * ) mc-compiler = [ feature.get-values : $(options) ] ; mc-compiler ?= mc ; - manifest-tool = mt ; - + manifest-tool = [ feature.get-values : $(options) ] ; + manifest-tool ?= mt ; + local cc-filter = [ feature.get-values : $(options) ] ; for local c in $(cpu) From ac9f7812247a1b80c06f28f6faf9c19dacb71989 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 25 Aug 2010 14:53:50 +0000 Subject: [PATCH 124/165] Remove OBJ/STATIC_LIB suffix specific for the qcc toolset. They duplicate the default definition, and therefore result in a 'duplicate key' error. [SVN r64994] --- v2/tools/qcc.jam | 6 ------ 1 file changed, 6 deletions(-) diff --git a/v2/tools/qcc.jam b/v2/tools/qcc.jam index 096e09c77..4f2a4fc14 100644 --- a/v2/tools/qcc.jam +++ b/v2/tools/qcc.jam @@ -25,12 +25,6 @@ generators.override builtin.lib-generator : qcc.prebuilt ; toolset.inherit-flags qcc : unix ; toolset.inherit-rules qcc : unix ; - -# Set typed target suffixes used by the qcc toolset. -type.set-generated-target-suffix OBJ : qcc : o ; -type.set-generated-target-suffix STATIC_LIB : qcc : a ; - - # Initializes the qcc toolset for the given version. If necessary, command may # be used to specify where the compiler is located. The parameter 'options' is a # space-delimited list of options, each one being specified as From dbafd0c39ddc7178fb0f88d09addfbd1852bf34a Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 25 Aug 2010 15:48:36 +0000 Subject: [PATCH 125/165] Pass arguments to bootstrap.bat over to jam's build.bat. [SVN r64998] --- v2/bootstrap.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/bootstrap.bat b/v2/bootstrap.bat index d2f0100d1..3fa2b199d 100644 --- a/v2/bootstrap.bat +++ b/v2/bootstrap.bat @@ -10,7 +10,7 @@ if exist ".\engine\src\bin.ntx86\bjam.exe" del engine\src\bin.ntx86\bjam.exe if exist ".\engine\src\bin.ntx86_64\bjam.exe" del engine\src\bin.ntx86_64\bjam.exe cd engine\src -call .\build.bat > ..\..\bootstrap.log +call .\build.bat %* > ..\..\bootstrap.log @ECHO OFF cd ..\.. From fd8f8b0ffe84c5c09590d2e4eed2b39fba5f206f Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 1 Sep 2010 08:40:17 +0000 Subject: [PATCH 126/165] Give a location to project-config.jam. Fixes #4615. [SVN r65163] --- v2/build-system.jam | 6 +++--- v2/build_system.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/v2/build-system.jam b/v2/build-system.jam index 67def964d..a555b610d 100644 --- a/v2/build-system.jam +++ b/v2/build-system.jam @@ -215,9 +215,9 @@ local rule find-target ( target-id ) # Initializes a new configuration module. # -local rule initialize-config-module ( module-name ) +local rule initialize-config-module ( module-name : location ? ) { - project.initialize $(module-name) ; + project.initialize $(module-name) : $(location) ; if USER_MODULE in [ RULENAMES ] { USER_MODULE $(module-name) ; @@ -419,7 +419,7 @@ local rule load-configuration-files } if $(file) { - initialize-config-module project-config ; + initialize-config-module project-config : $(file:D) ; load-config project-config : project-config.jam : $(file:D) ; } } diff --git a/v2/build_system.py b/v2/build_system.py index 6e33bee77..55d8b806c 100644 --- a/v2/build_system.py +++ b/v2/build_system.py @@ -172,9 +172,9 @@ def find_target(target_id): return result -def initialize_config_module(module_name): +def initialize_config_module(module_name, location=None): - get_manager().projects().initialize(module_name) + get_manager().projects().initialize(module_name, location) # Helper rule used to load configuration files. Loads the first configuration # file with the given 'filename' at 'path' into module with name 'module-name'. @@ -335,7 +335,7 @@ def load_configuration_files(): file = b2.util.path.glob_in_parents(".", ["project-config.jam"]) if file: - initialize_config_module('project-config') + initialize_config_module('project-config', os.path.dirname(file[0])) load_config('project-config', "project-config.jam", [os.path.dirname(file[0])], True) From 869d21c5ba5be3faca28e189038fa1d5d4d01da6 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 1 Sep 2010 09:02:49 +0000 Subject: [PATCH 127/165] Prevent double initialization of Jamfile in some cases. Fixes #4570. Thanks to Brian Freyburger for the patch. [SVN r65165] --- v2/build/project.jam | 25 +++++++++++++++---------- v2/build/project.py | 17 ++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/v2/build/project.jam b/v2/build/project.jam index b4d2227e6..4a8eb5607 100644 --- a/v2/build/project.jam +++ b/v2/build/project.jam @@ -294,18 +294,22 @@ local rule load-jamfile ( : "Filenames are: " $(jamfile-to-load:D=) ; } - # Initialize the Jamfile module before loading. - # - initialize $(jamfile-module) : [ path.parent $(jamfile-to-load) ] - : $(jamfile-to-load:BS) ; - - local saved-project = $(.current-project) ; - # Now load the Jamfile in it's own context. Initialization might have loaded - # parent Jamfiles, which might have loaded the current Jamfile with - # use-project. Do a final check to make sure it's not loaded already. + # Now load the Jamfile in it's own context. + # The call to 'initialize' may load parent Jamfile, which might have + # 'use-project' statement that causes a second attempt to load the + # same project we're loading now. Checking inside .jamfile-modules + # prevents that second attempt from messing up. 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) ] @@ -316,7 +320,7 @@ local rule load-jamfile ( load-aux $(jamfile-module) : [ path.native $(jamfile) ] ; } } - } + # Now do some checks. if $(.current-project) != $(saved-project) { @@ -346,6 +350,7 @@ local rule load-jamfile ( } } } + } } diff --git a/v2/build/project.py b/v2/build/project.py index f08e918ae..43fec9fb7 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -312,23 +312,22 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" dir = os.path.dirname(jamfile_to_load) if not dir: dir = "." - # Initialize the jamfile module before loading. - # - self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load)) saved_project = self.current_project self.used_projects[jamfile_module] = [] - # Now load the Jamfile in it's own context. - # Initialization might have load parent Jamfiles, which might have - # loaded the current Jamfile with use-project. Do a final check to make - # sure it's not loaded already. + # Now load the Jamfile in it's own context. + # The call to 'initialize' may load parent Jamfile, which might have + # 'use-project' statement that causes a second attempt to load the + # same project we're loading now. Checking inside .jamfile-modules + # prevents that second attempt from messing up. if not jamfile_module in self.jamfile_modules: self.jamfile_modules[jamfile_module] = True - # FIXME: - # mark-as-user $(jamfile-module) ; + # Initialize the jamfile module before loading. + # + self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load)) bjam.call("load", jamfile_module, jamfile_to_load) basename = os.path.basename(jamfile_to_load) From 48e08672f5b719e026bdd1d9a380f032dafdff8d Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 4 Sep 2010 10:10:34 +0000 Subject: [PATCH 128/165] Add 'strip-eol' option to SHELL. Also, return actual exit status. Previously, with the 'exit-code' option SHELL would return raw value from waitXXX, with exit status shifted 8 bits to the left. Fixes #4470. [SVN r65232] --- v2/engine/src/builtins.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/v2/engine/src/builtins.c b/v2/engine/src/builtins.c index b406dba69..524a39556 100644 --- a/v2/engine/src/builtins.c +++ b/v2/engine/src/builtins.c @@ -26,6 +26,8 @@ #include "timestamp.h" #include "md5.h" #include +# include +# include /* @@ -2170,6 +2172,14 @@ PyObject * bjam_caller( PyObject * self, PyObject * args ) #endif +static char * rtrim(char *s) +{ + char *p = s; + while(*p) ++p; + for(--p; p >= s && isspace(*p); *p-- = 0); + return s; +} + LIST * builtin_shell( PARSE * parse, FRAME * frame ) { LIST * command = lol_get( frame->args, 0 ); @@ -2181,6 +2191,7 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame ) int exit_status = -1; int exit_status_opt = 0; int no_output_opt = 0; + int strip_eol_opt = 0; /* Process the variable args options. */ { @@ -2196,6 +2207,10 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame ) { no_output_opt = 1; } + else if ( strcmp("strip-eol", arg->string) == 0 ) + { + strip_eol_opt = 1; + } arg = lol_get( frame->args, ++a ); } } @@ -2217,6 +2232,8 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame ) buffer[ret] = 0; if ( !no_output_opt ) { + if ( strip_eol_opt ) + rtrim(buffer); string_append( &s, buffer ); } } @@ -2230,6 +2247,10 @@ LIST * builtin_shell( PARSE * parse, FRAME * frame ) /* The command exit result next. */ if ( exit_status_opt ) { + if ( WIFEXITED(exit_status) ) + exit_status = WEXITSTATUS(exit_status); + else + exit_status = -1; sprintf( buffer, "%d", exit_status ); result = list_new( result, newstr( buffer ) ); } From d23f88930a768403a56ad04bc0d21c69772888c8 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 4 Sep 2010 12:27:39 +0000 Subject: [PATCH 129/165] Unbreak project loading in python port [SVN r65241] --- v2/build/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/v2/build/project.py b/v2/build/project.py index 43fec9fb7..74768b367 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -313,15 +313,13 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" if not dir: dir = "." - saved_project = self.current_project - self.used_projects[jamfile_module] = [] # Now load the Jamfile in it's own context. # The call to 'initialize' may load parent Jamfile, which might have # 'use-project' statement that causes a second attempt to load the # same project we're loading now. Checking inside .jamfile-modules - # prevents that second attempt from messing up. + # prevents that second attempt from messing up. if not jamfile_module in self.jamfile_modules: self.jamfile_modules[jamfile_module] = True @@ -329,6 +327,8 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" # self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load)) + saved_project = self.current_project + bjam.call("load", jamfile_module, jamfile_to_load) basename = os.path.basename(jamfile_to_load) From b417a942cdbc137eb5c24a5707cbf83634ce53bb Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 4 Sep 2010 12:29:10 +0000 Subject: [PATCH 130/165] Make toolset version relevant for configure checks. [SVN r65242] --- v2/build/configure.jam | 5 ++++- v2/build/configure.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/v2/build/configure.jam b/v2/build/configure.jam index 3edf98c89..c9a09b8c0 100644 --- a/v2/build/configure.jam +++ b/v2/build/configure.jam @@ -191,7 +191,10 @@ class check-target-builds-worker { # FIXME: this should not be hardcoded. Other checks might # want to consider different set of features as relevant. - local relevant = [ property.select + local toolset = [ property.select : $(properties) ] ; + local toolset-version-property = "" ; + local relevant = [ property.select $(toolset-version-property) + : $(properties) ] ; local ps = [ property-set.create $(relevant) ] ; local t = [ targets.current ] ; diff --git a/v2/build/configure.py b/v2/build/configure.py index 2c3e0534e..0426832c4 100644 --- a/v2/build/configure.py +++ b/v2/build/configure.py @@ -137,8 +137,11 @@ class CheckTargetBuildsWorker: # FIXME: this should not be hardcoded. Other checks might # want to consider different set of features as relevant. + toolset = ps.get('toolset')[0] + toolset_version_property = "" ; relevant = ps.get_properties('target-os') + \ ps.get_properties("toolset") + \ + ps.get_properties(toolset_version_property) + \ ps.get_properties("address-model") + \ ps.get_properties("architecture") rps = property_set.create(relevant) From cae3bfdd68874c0ef0dce9002dbe249655eced04 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 4 Sep 2010 12:39:20 +0000 Subject: [PATCH 131/165] Fix double-initializion of config files in Boost.Build/Python. [SVN r65243] --- v2/build/project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/v2/build/project.py b/v2/build/project.py index 74768b367..1e1e16fae 100644 --- a/v2/build/project.py +++ b/v2/build/project.py @@ -374,7 +374,6 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) the same file. """ - self.initialize(jamfile_module) self.used_projects[jamfile_module] = [] bjam.call("load", jamfile_module, file) self.load_used_projects(jamfile_module) From 87d4885c246a7c4e9a9e0f3991679c7672c1ecb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Hunold?= Date: Mon, 6 Sep 2010 14:14:09 +0000 Subject: [PATCH 132/165] Fix: windows does not have wait(), use own macros instead. [SVN r65319] --- v2/engine/src/builtins.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/v2/engine/src/builtins.c b/v2/engine/src/builtins.c index 524a39556..ae4bdfceb 100644 --- a/v2/engine/src/builtins.c +++ b/v2/engine/src/builtins.c @@ -26,9 +26,19 @@ #include "timestamp.h" #include "md5.h" #include + +#if defined(USE_EXECUNIX) # include # include - +#else +/* + NT does not have wait() and associated macros, it uses the return value + of system() instead. Status code group are documented at + http://msdn.microsoft.com/en-gb/library/ff565436.aspx +*/ +# define WIFEXITED(w) (((w) & 0XFFFFFF00) == 0) +# define WEXITSTATUS(w)(w) +#endif /* * builtins.c - builtin jam rules From 302866c325533365c465310d6217f63fb1394a83 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 23 Sep 2010 11:36:26 +0000 Subject: [PATCH 133/165] Various configure improvements [SVN r65541] --- v2/build/configure.jam | 44 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/v2/build/configure.jam b/v2/build/configure.jam index c9a09b8c0..fc0347753 100644 --- a/v2/build/configure.jam +++ b/v2/build/configure.jam @@ -14,6 +14,8 @@ import targets ; import errors ; import targets ; import sequence ; +import property ; +import property-set ; import "class" : new ; rule log-summary ( ) @@ -115,11 +117,11 @@ rule print-configure-checks-summary ( ) # Attempt to build a metatarget named by 'metatarget-reference' # in context of 'project' with properties 'ps'. # Returns non-empty value if build is OK. -rule builds ( metatarget-reference : project : ps : what ) +rule builds-raw ( metatarget-reference : project : ps : what : retry ? ) { local result ; - if ! $(.$(what)-tested.$(ps)) + if ! $(retry) && ! $(.$(what)-tested.$(ps)) { .$(what)-tested.$(ps) = true ; @@ -158,6 +160,25 @@ rule builds ( metatarget-reference : project : ps : what ) } } +rule builds ( metatarget-reference : properties * : what ? : retry ? ) +{ + what ?= "$(metatarget-reference) builds" ; + + # FIXME: this should not be hardcoded. Other checks might + # want to consider different set of features as relevant. + local toolset = [ property.select : $(properties) ] ; + local toolset-version-property = "" ; + local relevant = [ property.select $(toolset-version-property) + + : $(properties) ] ; + local ps = [ property-set.create $(relevant) ] ; + local t = [ targets.current ] ; + local p = [ $(t).project ] ; + + return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) : $(retry) ] ; +} + + # Called by Boost.Build startup code to specify name of a file # that will receive results of configure checks. This # should never be called by users. @@ -180,27 +201,18 @@ class check-target-builds-worker import targets ; import property ; - rule __init__ ( target : true-properties * : false-properties * ) + rule __init__ ( target message ? : true-properties * : false-properties * ) { self.target = $(target) ; + self.message = $(message) ; self.true-properties = $(true-properties) ; self.false-properties = $(false-properties) ; } rule check ( properties * ) { - # FIXME: this should not be hardcoded. Other checks might - # want to consider different set of features as relevant. - local toolset = [ property.select : $(properties) ] ; - local toolset-version-property = "" ; - local relevant = [ property.select $(toolset-version-property) - - : $(properties) ] ; - local ps = [ property-set.create $(relevant) ] ; - local t = [ targets.current ] ; - local p = [ $(t).project ] ; local choosen ; - if [ configure.builds $(self.target) : $(p) : $(ps) : "$(self.target) builds" ] + if [ configure.builds $(self.target) : $(properties) : $(self.message) ] { choosen = $(self.true-properties) ; } @@ -213,9 +225,9 @@ class check-target-builds-worker } -rule check-target-builds ( target : true-properties * : false-properties * ) +rule check-target-builds ( target message ? : true-properties * : false-properties * ) { - local instance = [ new check-target-builds-worker $(target) : $(true-properties) + local instance = [ new check-target-builds-worker $(target) $(message) : $(true-properties) : $(false-properties) ] ; return @$(instance).check ; } From 78aa937eccf2f622e82953333b08905cc67f4a25 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 27 Sep 2010 16:05:45 +0000 Subject: [PATCH 134/165] Add verification on gcc version and command. Most importantly, if version is specified and command is not, check for g++-$version and failing that, check if g++ -dumpversion returns the version we've asked about. Patch from Moritz Hassert. Addresses #4667. [SVN r65633] --- v2/tools/gcc.jam | 63 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/v2/tools/gcc.jam b/v2/tools/gcc.jam index 0584df477..92ce15046 100644 --- a/v2/tools/gcc.jam +++ b/v2/tools/gcc.jam @@ -58,11 +58,72 @@ type.set-generated-target-suffix OBJ : gcc cygwin : o ; # Example: # using gcc : 3.4 : : foo bar sun ; # +# The compiler command to use is detected in a three step manner: +# 1) If an explicit command is specified by the user, it will be used and must available. +# 2) If only a certain version is specified, it is enforced: +# - either a command 'g++-VERSION' must be available +# - or the default command 'g++' must be available and match the exact version. +# 3) Without user-provided restrictions use default 'g++' rule init ( version ? : command * : options * ) { + #1): use user-provided command + local tool-command = ; + if $(command) + { + tool-command = [ common.get-invocation-command-nodefault gcc : g++ : $(command) ] ; + if ! $(tool-command) + { + errors.error "toolset gcc initialization:" : + "provided command '$(command)' not found" : + "initialized from" [ errors.nearest-user-location ] ; + } + } + #2): enforce user-provided version + else if $(version) + { + tool-command = [ common.get-invocation-command-nodefault gcc : "g++-$(version[1])" ] ; + + #2.1) fallback: check whether "g++" reports the requested version + if ! $(tool-command) + { + tool-command = [ common.get-invocation-command-nodefault gcc : g++ ] ; + if $(tool-command) + { + local tool-command-string = $(tool-command:J=" ") ; + local tool-version = [ MATCH "^([0-9.]+)" : [ SHELL "$(tool-command-string) -dumpversion" ] ] ; + ECHO "XXX" $(tool-version) ; + if $(tool-version) != $(version) + { + errors.error "toolset gcc initialization:" : + "version '$(version)' requested but 'g++-$(version)' not found and version '$(tool-version)' of default '$(tool-command)' does not match" : + "initialized from" [ errors.nearest-user-location ] ; + tool-command = ; + } + } + else + { + errors.error "toolset gcc initialization:" : + "version '$(version)' requested but neither 'g++-$(version)' nor default 'g++' found" : + "initialized from" [ errors.nearest-user-location ] ; + } + } + } + #3) default: no command and no version specified, try using default command "g++" + else + { + tool-command = [ common.get-invocation-command-nodefault gcc : g++ ] ; + if ! $(tool-command) + { + errors.error "toolset gcc initialization:" : + "no command provided, default command 'g++' not found" : + "initialized from" [ errors.nearest-user-location ] ; + } + } + + # Information about the gcc command... # The command. - local command = [ common.get-invocation-command gcc : g++ : $(command) ] ; + local command = $(tool-command) ; # The root directory of the tool install. local root = [ feature.get-values : $(options) ] ; # The bin directory where to find the command to execute. From 336ee7936a93203626df5a55b9e3a78df700f341 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Mon, 27 Sep 2010 16:39:37 +0000 Subject: [PATCH 135/165] Relax the check between user-specified version and the one from 'g++'. Fixes #4667. [SVN r65640] --- v2/tools/gcc.jam | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/v2/tools/gcc.jam b/v2/tools/gcc.jam index 92ce15046..c6f4fe037 100644 --- a/v2/tools/gcc.jam +++ b/v2/tools/gcc.jam @@ -91,13 +91,24 @@ rule init ( version ? : command * : options * ) { local tool-command-string = $(tool-command:J=" ") ; local tool-version = [ MATCH "^([0-9.]+)" : [ SHELL "$(tool-command-string) -dumpversion" ] ] ; - ECHO "XXX" $(tool-version) ; if $(tool-version) != $(version) { - errors.error "toolset gcc initialization:" : - "version '$(version)' requested but 'g++-$(version)' not found and version '$(tool-version)' of default '$(tool-command)' does not match" : - "initialized from" [ errors.nearest-user-location ] ; - tool-command = ; + # Permit a match betwen two-digit version specified by the user + # (e.g. 4.4) and 3-digit version reported by gcc. + # Since only two digits are present in binary name anyway, + # insisting that user specify 3-digit version when + # configuring Boost.Build while it's not required on + # command like would be strange. + local stripped = [ MATCH "^([0-9]+\.[0-9]+).*" : $(tool-version) ] ; + if $(stripped) != $(version) + { + errors.error "toolset gcc initialization:" : + "version '$(version)' requested but 'g++-$(version)' not found and version '$(tool-version)' of default '$(tool-command)' does not match" : + "initialized from" [ errors.nearest-user-location ] ; + tool-command = ; + } + # Use full 3-digit version to be compatible with the 'using gcc ;' case + version = $(tool-version) ; } } else From 1295ff8286e53ab032e9197c33ef0ef416d63447 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 6 Oct 2010 18:30:15 +0000 Subject: [PATCH 136/165] Fix references to 'testing' section [SVN r65785] --- v2/doc/src/reference.xml | 4 ++-- v2/doc/src/tutorial.xml | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/v2/doc/src/reference.xml b/v2/doc/src/reference.xml index bb838d403..a880ab141 100644 --- a/v2/doc/src/reference.xml +++ b/v2/doc/src/reference.xml @@ -95,7 +95,7 @@ boost-build build-system ; unit-test Creates an executable that will be automatically run. See - . + . @@ -107,7 +107,7 @@ boost-build build-system ; run-fail Specialized rules for testing. See - . + . diff --git a/v2/doc/src/tutorial.xml b/v2/doc/src/tutorial.xml index 19c387efa..3763471df 100644 --- a/v2/doc/src/tutorial.xml +++ b/v2/doc/src/tutorial.xml @@ -431,10 +431,6 @@ project -
- Testing -
-
Static and shared libaries From 06e2eb20a5681b42948184d49d4d03d8a55beb68 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 6 Oct 2010 18:34:31 +0000 Subject: [PATCH 137/165] Remove "V2 vs. V1" section, since it's likely irrelevant now. [SVN r65786] --- v2/doc/src/standalone.xml | 2 - v2/doc/src/userman.xml | 1 - v2/doc/src/v1_vs_v2.xml | 111 -------------------------------------- 3 files changed, 114 deletions(-) delete mode 100644 v2/doc/src/v1_vs_v2.xml diff --git a/v2/doc/src/standalone.xml b/v2/doc/src/standalone.xml index 1e8efa656..633f52ad1 100644 --- a/v2/doc/src/standalone.xml +++ b/v2/doc/src/standalone.xml @@ -41,8 +41,6 @@ - - diff --git a/v2/doc/src/userman.xml b/v2/doc/src/userman.xml index 915027dfa..606aa6dfd 100644 --- a/v2/doc/src/userman.xml +++ b/v2/doc/src/userman.xml @@ -36,6 +36,5 @@ - diff --git a/v2/doc/src/v1_vs_v2.xml b/v2/doc/src/v1_vs_v2.xml deleted file mode 100644 index 91b639cf5..000000000 --- a/v2/doc/src/v1_vs_v2.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - - - Differences to Boost.Build V1 - - - While Boost.Build V2 is based on the same ideas as Boost.Build V1, - some of the syntax was changed, and some new important features were - added. This chapter describes most of the changes. - -
- Configuration - - In V1, toolsets were configured by environment variables. If you - wanted to use two versions of the same toolset, you had to create a new - toolset module that would set the variables and then invoke the base - toolset. In V2, toolsets are configured by the - using, and you can easily configure several - versions of a toolset. See for details. - - -
- -
- Writing Jamfiles - - Probably one of the most important differences in V2 Jamfiles is - the use of project requirements. In V1, if several targets had the same - requirements (for example, a common #include path), it was necessary to - manually write the requirements or use a helper rule or template target. In V2, the - common properties can be specified with the requirements project - attribute, as documented in . - - - Usage requirements - also help to simplify Jamfiles. - - If a library requires - all clients to use specific #include paths or macros when compiling - code that depends on the library, that information can be cleanly - represented. - - The difference between lib and dll targets in V1 is completely - eliminated in V2. There's only one library target type, lib, which can create - either static or shared libraries depending on the value of the - <link> - feature. If your target should be only built in one way, you - can add <link>shared or <link>static to its requirements. - - - The syntax for referring to other targets was changed a bit. While - in V1 one would use: - -exe a : a.cpp <lib>../foo/bar ; - - the V2 syntax is: - -exe a : a.cpp ../foo//bar ; - - Note that you don't need to specify the type of other target, but the - last element should be separated from the others by a double slash to indicate that - you're referring to target bar in project ../foo, and not to - project ../foo/bar. - - - -
- -
- Build process - - The command line syntax in V2 is completely different. For example - -bjam -sTOOLS=msvc -sBUILD=release some_target - - now becomes: - -bjam toolset=msvc variant=release some_target - - or, using implicit features, just: - -bjam msvc release some_target - - See the reference for a - complete description of the syntax. - - - -
-
- - - From 12d79bffdfd13cade19079f557f74e4f7b274d12 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 6 Oct 2010 20:18:09 +0000 Subject: [PATCH 138/165] Kill some sections in jam docs. Expand list of options in Boost.Build docs. [SVN r65790] --- v2/doc/bjam.qbk | 192 -------------------------------------- v2/doc/src/overview.xml | 72 +++++++++++--- v2/doc/src/standalone.xml | 2 +- 3 files changed, 58 insertions(+), 208 deletions(-) diff --git a/v2/doc/bjam.qbk b/v2/doc/bjam.qbk index 300a1f8c9..95207332d 100644 --- a/v2/doc/bjam.qbk +++ b/v2/doc/bjam.qbk @@ -44,33 +44,6 @@ [template lines[items]''''''[items]''''''] [template line[text]''''''[text]''''''] -[section:intro Introduction] - -[warning Most probably, you are looking for [@http://boost.org/boost-build2/doc/html/index.html Boost.Build -manual]. This document is not meant to be read standalone and will only -confuse you. Boost.Build manual refers to specific sections when necessary.] - -Boost.Jam (BJam) is the low-level build engine tool for -[@http://boost.org/boost-build2 Boost.Build]. Historically, Boost.Jam is based -on on FTJam and on :Perforce_Jam: but has grown a number of significant -features and is now developed independently, with no merge back expected to -happen, and little use outside Boost.Build. - -This is version :version: of BJam and is based on version 2.4 of Jam/MR: - -[pre -/+\ -+\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. -\+/ -This is Release 2.4 of Jam/MR, a make-like program. -License is hereby granted to use this software and distribute it -freely, as long as this copyright notice is retained and modifications -are clearly marked. -ALL WARRANTIES ARE HEREBY DISCLAIMED. -] - -[endsect] - [section:building Building BJam] Installing =BJam= after building it is simply a matter of copying the @@ -406,171 +379,6 @@ The arguments starting with the "=--option=" forms are passed to the =build.jam= [endsect] -[section:usage Using BJam] - -[warning Most probably, you are looking for -[@http://boost.org/boost-build2/doc/html/index.html Boost.Build -manual] or [@http://www.boost.org/boost-build2/doc/html/bbv2/overview/invocation.html Boost.Build -command-line syntax]. This section documents only low-level options used by -the Boost.Jam build engine, and does not mention any high-level syntax of Boost.Build] - - -If /target/ is provided on the command line, =bjam= builds /target/; otherwise =bjam= builds the target =all=. - -[pre -bjam ( -option \[value\] | target ) * -] - -[section:options Options] - -Options are either singular or have an accompanying value. When a value is allowed, or required, it can be either given as an argument following the option argument, or it can be given immediately after the option as part of the option argument. The allowed options are: - -[variablelist - - [ [[literal -a]] - [Build all targets anyway, even if they are up-to-date.] ] - - [ [[literal -d /n/]] - [ - Enable cummulative debugging levels from 1 to n. Values are: - - [orderedlist - [li Show the actions taken for building targets, as they are executed (the default).] - [li Show "quiet" actions and display all action text, as they are executed.] - [li Show dependency analysis, and target/source timestamps/paths.] - [li Show arguments and timming of shell invocations.] - [li Show rule invocations and variable expansions.] - [li Show directory/header file/archive scans, and attempts at binding to targets.] - [li Show variable settings.] - [li Show variable fetches, variable expansions, and evaluation of '"if"' expressions.] - [li Show variable manipulation, scanner tokens, and memory usage.] - [li Show profile information for rules, both timing and memory.] - [li Show parsing progress of Jamfiles.] - [li Show graph of target dependencies.] - [li Show change target status (fate).] - ] - ] ] - - [ [[literal -d +/n/]] - [Enable debugging level /n/.] ] - - [ [[literal -d 0]] - [Turn off all debugging levels. Only errors are reported.] ] - - [ [[literal -f /Jambase/]] [Read /Jambase/ instead of using the built-in - Jambase. Only one -f flag is permitted, but the /Jambase/ may explicitly - include other files. A /Jambase/ name of "-" is allowed, in which case - console input is read until it is closed, at which point the input is - treated as the Jambase.] ] - - [ [[literal -j /n/]] - [Run up to /n/ shell commands concurrently (UNIX and NT only). The default is 1.] ] - - [ [[literal -l /n/]] - [Limit actions to running for /n/ number of seconds, after which they are stopped. Note: Windows only.] ] - - [ [[literal -n]] - [Don't actually execute the updating actions, but do everything else. This changes the debug level default to =-d 2=.] ] - - [ [[literal -o /file/]] - [Write the updating actions to the specified file instead of running them.] ] - - [ [[literal -q]] - [Quit quickly (as if an interrupt was received) as soon as *any* target fails.] ] - - [ [[literal -s /var/=/value/]] - [Set the variable /var/ to /value/, overriding both internal variables and variables imported from the environment.] ] - - [ [[literal -t /target/]] - [Rebuild /target/ and everything that depends on it, even if it is up-to-date.] ] - - [ [[literal -- /value/]] - [The option and /value/ is ignored, but is available from the =$(ARGV)= variable. ]] - - [ [[literal -v]] - [Print the version of =bjam= and exit.] ] -] - -[section Command-line and Environment Variable Quoting] - -Classic Jam had an odd behavior with respect to command-line variable (=-s...=) and environment variable settings which made it impossible to define an arbitrary variable with spaces in the value. Boost Jam remedies that by treating all such settings as a single string if they are surrounded by double-quotes. Uses of this feature can look interesting, since shells require quotes to keep characters separated by whitespace from being treated as separate arguments: - -[pre -jam -sMSVCNT="\\"\\"C:\\Program Files\\Microsoft Visual C++\\VC98\\"\\"" ... -] - -The outer quote is for the shell. The middle quote is for Jam, to tell it to take everything within those quotes literally, and the inner quotes are for the shell again when paths are passed as arguments to build actions. Under NT, it looks a lot more sane to use environment variables before invoking jam when you have to do this sort of quoting: - -[pre -set MSVCNT=""C:\\Program Files\\Microsoft Visual C++\\VC98\\"" -] - -[endsect] - -[endsect] - -[section:operation Operation] - -BJam has four phases of operation: start-up, parsing, binding, and updating. - -[section:startup Start-up] - -Upon start-up, =bjam= imports environment variable settings into =bjam= variables. Environment variables are split at blanks with each word becoming an element in the variable's list of values. Environment variables whose names end in =PATH= are split at =$(SPLITPATH)= characters (e.g., =":"= for Unix). - -To set a variable's value on the command line, overriding the variable's environment value, use the =-s= option. To see variable assignments made during bjam's execution, use the =-d+7= option. - -The Boost.Build v2 initialization behavior has been implemented. This behavior only applies when the executable being invoked is called "=bjam=" or, for backward-compatibility, when the =BOOST_ROOT= variable is set. - -# We attempt to load "=boost-build.jam=" by searching from the current invocation directory up to the root of the file system. This file is expected to invoke the =boost-build= rule to indicate where the Boost.Build system files are, and to load them. - -# If =boost-build.jam= is not found we error and exit, giving brief instructions on possible errors. As a backward-compatibility measure for older versions of Boost.Build, when the =BOOST_ROOT= variable is set, we first search for =boost-build.jam= in =$(BOOST_ROOT)/tools/build= and =$(BOOST_BUILD_PATH)=. If found, it is loaded and initialization is complete. - -# The =boost-build= rule adds its (optional) argument to the front of =BOOST_BUILD_PATH=, and attempts to load =bootstrap.jam= from those directories. If a relative path is specified as an argument, it is treated as though it was relative to the =boost-build.jam= file. - -# If the =bootstrap.jam= file was not found, we print a likely error message and exit. - -[endsect] - -[section:parsing Parsing] - -In the parsing phase, =bjam= reads and parses the =Jambase= file, by default the built-in one. It is written in the [link jam.language jam language]. The last action of the =Jambase= is to read (via the "include" rule) a user-provided file called "=Jamfile=". - -Collectively, the purpose of the =Jambase= and the =Jamfile= is to name build targets and source files, construct the dependency graph among them, and associate build actions with targets. The =Jambase= defines boilerplate rules and variable assignments, and the =Jamfile= uses these to specify the actual relationship among the target and source files. - -[endsect] - -[section:binding Binding] - -After parsing, =bjam= recursively descends the dependency graph and binds every file target with a location in the filesystem. If =bjam= detects a circular dependency in the graph, it issues a warning. - -File target names are given as absolute or relative path names in the filesystem. If the path name is absolute, it is bound as is. If the path name is relative, it is normally bound as is, and thus relative to the current directory. This can be modified by the settings of the =$(SEARCH)= and =$(LOCATE)= variables, which enable jam to find and build targets spread across a directory tree. See [link jam.language.variables.builtins.search SEARCH and LOCATE Variables] below. - -[section:fate Update Determination] - -After binding each target, =bjam= determines whether the target needs updating, and if so marks the target for the updating phase. A target is normally so marked if it is missing, it is older than any of its sources, or any of its sources are marked for updating. This behavior can be modified by the application of special built-in rules, =ALWAYS=, =LEAVES=, =NOCARE=, =NOTFILE=, =NOUPDATE=, and =TEMPORARY=. See [link jam.language.rules.builtins.modifying_binding Modifying Binding] below. - -[endsect] - -[section:headerscan Header File Scanning] - -During the binding phase, =bjam= also performs header file scanning, where it looks inside source files for the implicit dependencies on other files caused by C's #include syntax. This is controlled by the special variables $(HDRSCAN) and $(HDRRULE). The result of the scan is formed into a rule invocation, with the scanned file as the target and the found included file names as the sources. Note that this is the only case where rules are invoked outside the parsing phase. See [link jam.language.variables.builtins.hdrscan HDRSCAN and HDRRULE Variables] below. - -[endsect] - -[endsect] - -[section:updating Updating] - -After binding, =bjam= again recursively descends the dependency graph, this time executing the update actions for each target marked for update during the binding phase. If a target's updating actions fail, then all other targets which depend on that target are skipped. - -The =-j= flag instructs =bjam= to build more than one target at a time. If there are multiple actions on a single target, they are run sequentially. - -[endsect] - -[endsect] - -[endsect] - [section:language Language] =BJam= has an interpreted, procedural language. Statements in =bjam= are rule (procedure) definitions, rule invocations, flow-of-control structures, variable assignments, and sundry language support. diff --git a/v2/doc/src/overview.xml b/v2/doc/src/overview.xml index e6d72e53e..048898867 100644 --- a/v2/doc/src/overview.xml +++ b/v2/doc/src/overview.xml @@ -710,20 +710,6 @@ bjam toolset=gcc variant=debug optimization=space - - - - Show commands as they are executed. - - - - - - - Supress all informational messages. - - - @@ -771,7 +757,63 @@ bjam toolset=gcc variant=debug optimization=space user-config.jam configuration files. - + + + + + + Supress all informational messages. + + + + + + + Enable cummulative debugging levels from 1 to n. Values are: + + Show the actions taken for building targets, as they are executed (the default). + Show "quiet" actions and display all action text, as they are executed. + Show dependency analysis, and target/source timestamps/paths. + Show arguments and timming of shell invocations. + Show rule invocations and variable expansions. + Show directory/header file/archive scans, and attempts at binding to targets. + Show variable settings. + Show variable fetches, variable expansions, and evaluation of '"if"' expressions. + Show variable manipulation, scanner tokens, and memory usage. + Show profile information for rules, both timing and memory. + Show parsing progress of Jamfiles. + Show graph of target dependencies. + Show change target status (fate). + + + + + + + + + Enable debugging level N. + + + + + + + Write the updating actions to the specified file instead of running them. + + + + + + + + Set the variable var to + value in the global scope of the jam + language interpreter, overriding variables imported from the + environment. + + +
diff --git a/v2/doc/src/standalone.xml b/v2/doc/src/standalone.xml index 633f52ad1..2666cd1d4 100644 --- a/v2/doc/src/standalone.xml +++ b/v2/doc/src/standalone.xml @@ -39,7 +39,7 @@ Boost.Jam Documentation + xpointer="xpointer(id('jam.building')|id('jam.building')/following-sibling::*)"/> From c123c1e1fa11bd5184240d6b72537744a1d4ffb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Hunold?= Date: Fri, 8 Oct 2010 17:48:40 +0000 Subject: [PATCH 139/165] Fix: adjust toolset-tag to changed toolset definition. [SVN r65838] --- v2/tools/common.jam | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/v2/tools/common.jam b/v2/tools/common.jam index f56b9d00e..df914d9d4 100644 --- a/v2/tools/common.jam +++ b/v2/tools/common.jam @@ -825,8 +825,14 @@ local rule toolset-tag ( name : type ? : property-set ) switch [ $(property-set).get ] { case borland* : tag += bcb ; - case clang-unix* : tag += gcc ; - case clang-darwin* : tag += xgcc ; + case clang* : + { + switch [ $(property-set).get ] + { + case darwin : tag += clang-darwin ; + case linux : tag += clang ; + } + } case como* : tag += como ; case cw : tag += cw ; case darwin* : tag += xgcc ; From 79ab6f1734780b4d7dba3709b50d4fc513636d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Hunold?= Date: Wed, 20 Oct 2010 15:56:49 +0000 Subject: [PATCH 140/165] do not clear flags already set by common.handle-options in init() [SVN r66117] --- v2/tools/clang-linux.jam | 4 ---- 1 file changed, 4 deletions(-) diff --git a/v2/tools/clang-linux.jam b/v2/tools/clang-linux.jam index ff477d4b6..2ab4db559 100644 --- a/v2/tools/clang-linux.jam +++ b/v2/tools/clang-linux.jam @@ -70,10 +70,6 @@ rule init ( version ? : command * : options * ) SPACE = " " ; -flags clang-linux.compile OPTIONS ; -flags clang-linux.compile OPTIONS ; -# flags clang-linux.compile INCLUDES ; - # Declare flags and action for compilation. toolset.flags clang-linux.compile OPTIONS off : -O0 ; toolset.flags clang-linux.compile OPTIONS speed : -O3 ; From d3fbe75433e278a676e8cf45ec41c4a29f4df847 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sat, 30 Oct 2010 14:32:50 +0000 Subject: [PATCH 141/165] Link fixes. [SVN r66273] --- v2/engine/index.html | 4 ++-- v2/test/test_system.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/v2/engine/index.html b/v2/engine/index.html index 61bfe50ba..b97e2355e 100644 --- a/v2/engine/index.html +++ b/v2/engine/index.html @@ -3,7 +3,7 @@ - + - - - - - - - Automatic redirection failed, please go to
../../../../doc/html/jam.html - - diff --git a/v2/test/engine/README.txt b/v2/test/engine/README.txt new file mode 100644 index 000000000..c38701fb8 --- /dev/null +++ b/v2/test/engine/README.txt @@ -0,0 +1,5 @@ + +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/v2/engine/test/action_status.jam b/v2/test/engine/action_status.jam similarity index 100% rename from v2/engine/test/action_status.jam rename to v2/test/engine/action_status.jam diff --git a/v2/engine/test/actions_quietly.jam b/v2/test/engine/actions_quietly.jam similarity index 100% rename from v2/engine/test/actions_quietly.jam rename to v2/test/engine/actions_quietly.jam diff --git a/v2/engine/test/builtin_normalize_path.jam b/v2/test/engine/builtin_normalize_path.jam similarity index 100% rename from v2/engine/test/builtin_normalize_path.jam rename to v2/test/engine/builtin_normalize_path.jam diff --git a/v2/engine/test/builtin_shell.jam b/v2/test/engine/builtin_shell.jam similarity index 100% rename from v2/engine/test/builtin_shell.jam rename to v2/test/engine/builtin_shell.jam diff --git a/v2/engine/test/builtin_w32_getregnames.jam b/v2/test/engine/builtin_w32_getregnames.jam similarity index 100% rename from v2/engine/test/builtin_w32_getregnames.jam rename to v2/test/engine/builtin_w32_getregnames.jam diff --git a/v2/engine/test/option_d2.jam b/v2/test/engine/option_d2.jam similarity index 100% rename from v2/engine/test/option_d2.jam rename to v2/test/engine/option_d2.jam diff --git a/v2/engine/test/option_l.jam b/v2/test/engine/option_l.jam similarity index 100% rename from v2/engine/test/option_l.jam rename to v2/test/engine/option_l.jam diff --git a/v2/engine/test/option_n.jam b/v2/test/engine/option_n.jam similarity index 100% rename from v2/engine/test/option_n.jam rename to v2/test/engine/option_n.jam diff --git a/v2/engine/test/parallel_actions.jam b/v2/test/engine/parallel_actions.jam similarity index 100% rename from v2/engine/test/parallel_actions.jam rename to v2/test/engine/parallel_actions.jam diff --git a/v2/engine/test/parallel_multifile_actions_1.jam b/v2/test/engine/parallel_multifile_actions_1.jam similarity index 100% rename from v2/engine/test/parallel_multifile_actions_1.jam rename to v2/test/engine/parallel_multifile_actions_1.jam diff --git a/v2/engine/test/parallel_multifile_actions_2.jam b/v2/test/engine/parallel_multifile_actions_2.jam similarity index 100% rename from v2/engine/test/parallel_multifile_actions_2.jam rename to v2/test/engine/parallel_multifile_actions_2.jam diff --git a/v2/engine/test/rule_param.jam b/v2/test/engine/rule_param.jam similarity index 100% rename from v2/engine/test/rule_param.jam rename to v2/test/engine/rule_param.jam diff --git a/v2/engine/test/stress_var_expand.jam b/v2/test/engine/stress_var_expand.jam similarity index 100% rename from v2/engine/test/stress_var_expand.jam rename to v2/test/engine/stress_var_expand.jam diff --git a/v2/engine/test/target_var.jam b/v2/test/engine/target_var.jam similarity index 100% rename from v2/engine/test/target_var.jam rename to v2/test/engine/target_var.jam diff --git a/v2/engine/test/test.bat b/v2/test/engine/test.bat similarity index 100% rename from v2/engine/test/test.bat rename to v2/test/engine/test.bat diff --git a/v2/engine/test/test.jam b/v2/test/engine/test.jam similarity index 100% rename from v2/engine/test/test.jam rename to v2/test/engine/test.jam diff --git a/v2/engine/test/test.sh b/v2/test/engine/test.sh similarity index 100% rename from v2/engine/test/test.sh rename to v2/test/engine/test.sh diff --git a/v2/engine/test/var_expand.jam b/v2/test/engine/var_expand.jam similarity index 100% rename from v2/engine/test/var_expand.jam rename to v2/test/engine/var_expand.jam From c5c0853519e6a7188026cb98853d0fe4540cd504 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 1 Feb 2011 08:16:47 +0000 Subject: [PATCH 164/165] Kill 'engine/src', moving all content to 'engine'. [SVN r68592] --- v2/bootstrap.bat | 14 +++++++------- v2/bootstrap.sh | 10 +++++----- v2/engine/{src => }/Jambase | 0 v2/engine/{src => }/boehm_gc/AmigaOS.c | 0 v2/engine/{src => }/boehm_gc/BCC_MAKEFILE | 0 v2/engine/{src => }/boehm_gc/ChangeLog | 0 v2/engine/{src => }/boehm_gc/EMX_MAKEFILE | 0 v2/engine/{src => }/boehm_gc/MacOS.c | 0 v2/engine/{src => }/boehm_gc/MacProjects.sit.hqx | 0 .../boehm_gc/Mac_files/MacOS_Test_config.h | 0 .../{src => }/boehm_gc/Mac_files/MacOS_config.h | 0 v2/engine/{src => }/boehm_gc/Mac_files/dataend.c | 0 .../{src => }/boehm_gc/Mac_files/datastart.c | 0 v2/engine/{src => }/boehm_gc/Makefile.DLLs | 0 v2/engine/{src => }/boehm_gc/Makefile.am | 0 v2/engine/{src => }/boehm_gc/Makefile.direct | 0 v2/engine/{src => }/boehm_gc/Makefile.dj | 0 v2/engine/{src => }/boehm_gc/Makefile.in | 0 v2/engine/{src => }/boehm_gc/NT_MAKEFILE | 0 .../{src => }/boehm_gc/NT_STATIC_THREADS_MAKEFILE | 0 v2/engine/{src => }/boehm_gc/NT_THREADS_MAKEFILE | 0 .../boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE | 0 v2/engine/{src => }/boehm_gc/OS2_MAKEFILE | 0 v2/engine/{src => }/boehm_gc/PCR-Makefile | 0 v2/engine/{src => }/boehm_gc/README.QUICK | 0 v2/engine/{src => }/boehm_gc/SMakefile.amiga | 0 v2/engine/{src => }/boehm_gc/WCC_MAKEFILE | 0 v2/engine/{src => }/boehm_gc/acinclude.m4 | 0 v2/engine/{src => }/boehm_gc/aclocal.m4 | 0 v2/engine/{src => }/boehm_gc/add_gc_prefix.c | 0 v2/engine/{src => }/boehm_gc/allchblk.c | 0 v2/engine/{src => }/boehm_gc/alloc.c | 0 v2/engine/{src => }/boehm_gc/alpha_mach_dep.S | 0 v2/engine/{src => }/boehm_gc/backgraph.c | 0 v2/engine/{src => }/boehm_gc/bdw-gc.pc | 0 v2/engine/{src => }/boehm_gc/bdw-gc.pc.in | 0 v2/engine/{src => }/boehm_gc/blacklst.c | 0 v2/engine/{src => }/boehm_gc/callprocs | 0 v2/engine/{src => }/boehm_gc/checksums.c | 0 v2/engine/{src => }/boehm_gc/compile | 0 v2/engine/{src => }/boehm_gc/config.guess | 0 v2/engine/{src => }/boehm_gc/config.sub | 0 v2/engine/{src => }/boehm_gc/configure | 0 v2/engine/{src => }/boehm_gc/configure.ac | 0 v2/engine/{src => }/boehm_gc/configure.host | 0 .../{src => }/boehm_gc/configure_atomic_ops.sh | 0 v2/engine/{src => }/boehm_gc/cord/cord.am | 0 v2/engine/{src => }/boehm_gc/cord/cordbscs.c | 0 v2/engine/{src => }/boehm_gc/cord/cordprnt.c | 0 v2/engine/{src => }/boehm_gc/cord/cordtest.c | 0 v2/engine/{src => }/boehm_gc/cord/cordxtra.c | 0 v2/engine/{src => }/boehm_gc/cord/de.c | 0 v2/engine/{src => }/boehm_gc/cord/de_cmds.h | 0 v2/engine/{src => }/boehm_gc/cord/de_win.ICO | Bin v2/engine/{src => }/boehm_gc/cord/de_win.RC | 0 v2/engine/{src => }/boehm_gc/cord/de_win.c | 0 v2/engine/{src => }/boehm_gc/cord/de_win.h | 0 v2/engine/{src => }/boehm_gc/darwin_stop_world.c | 0 v2/engine/{src => }/boehm_gc/dbg_mlc.c | 0 v2/engine/{src => }/boehm_gc/depcomp | 0 v2/engine/{src => }/boehm_gc/digimars.mak | 0 v2/engine/{src => }/boehm_gc/doc/README | 0 v2/engine/{src => }/boehm_gc/doc/README.DGUX386 | 0 v2/engine/{src => }/boehm_gc/doc/README.Mac | 0 v2/engine/{src => }/boehm_gc/doc/README.MacOSX | 0 v2/engine/{src => }/boehm_gc/doc/README.OS2 | 0 v2/engine/{src => }/boehm_gc/doc/README.amiga | 0 v2/engine/{src => }/boehm_gc/doc/README.arm.cross | 0 v2/engine/{src => }/boehm_gc/doc/README.autoconf | 0 v2/engine/{src => }/boehm_gc/doc/README.changes | 0 .../{src => }/boehm_gc/doc/README.contributors | 0 v2/engine/{src => }/boehm_gc/doc/README.cords | 0 v2/engine/{src => }/boehm_gc/doc/README.darwin | 0 v2/engine/{src => }/boehm_gc/doc/README.dj | 0 .../{src => }/boehm_gc/doc/README.environment | 0 v2/engine/{src => }/boehm_gc/doc/README.ews4800 | 0 v2/engine/{src => }/boehm_gc/doc/README.hp | 0 v2/engine/{src => }/boehm_gc/doc/README.linux | 0 v2/engine/{src => }/boehm_gc/doc/README.macros | 0 v2/engine/{src => }/boehm_gc/doc/README.rs6000 | 0 v2/engine/{src => }/boehm_gc/doc/README.sgi | 0 v2/engine/{src => }/boehm_gc/doc/README.solaris2 | 0 v2/engine/{src => }/boehm_gc/doc/README.uts | 0 v2/engine/{src => }/boehm_gc/doc/README.win32 | 0 v2/engine/{src => }/boehm_gc/doc/README.win64 | 0 v2/engine/{src => }/boehm_gc/doc/barrett_diagram | 0 v2/engine/{src => }/boehm_gc/doc/debugging.html | 0 v2/engine/{src => }/boehm_gc/doc/doc.am | 0 v2/engine/{src => }/boehm_gc/doc/gc.man | 0 v2/engine/{src => }/boehm_gc/doc/gcdescr.html | 0 v2/engine/{src => }/boehm_gc/doc/gcinterface.html | 0 v2/engine/{src => }/boehm_gc/doc/leak.html | 0 v2/engine/{src => }/boehm_gc/doc/overview.html | 0 v2/engine/{src => }/boehm_gc/doc/porting.html | 0 v2/engine/{src => }/boehm_gc/doc/scale.html | 0 .../{src => }/boehm_gc/doc/simple_example.html | 0 v2/engine/{src => }/boehm_gc/doc/tree.html | 0 v2/engine/{src => }/boehm_gc/dyn_load.c | 0 v2/engine/{src => }/boehm_gc/finalize.c | 0 v2/engine/{src => }/boehm_gc/gc.mak | 0 v2/engine/{src => }/boehm_gc/gc_cpp.cc | 0 v2/engine/{src => }/boehm_gc/gc_cpp.cpp | 0 v2/engine/{src => }/boehm_gc/gc_dlopen.c | 0 v2/engine/{src => }/boehm_gc/gcj_mlc.c | 0 v2/engine/{src => }/boehm_gc/gcname.c | 0 v2/engine/{src => }/boehm_gc/headers.c | 0 .../{src => }/boehm_gc/hpux_test_and_clear.s | 0 .../{src => }/boehm_gc/ia64_save_regs_in_stack.s | 0 v2/engine/{src => }/boehm_gc/if_mach.c | 0 v2/engine/{src => }/boehm_gc/if_not_there.c | 0 v2/engine/{src => }/boehm_gc/include/cord.h | 0 v2/engine/{src => }/boehm_gc/include/ec.h | 0 v2/engine/{src => }/boehm_gc/include/gc.h | 0 .../{src => }/boehm_gc/include/gc_allocator.h | 0 .../boehm_gc/include/gc_amiga_redirects.h | 0 v2/engine/{src => }/boehm_gc/include/gc_backptr.h | 0 .../{src => }/boehm_gc/include/gc_config_macros.h | 0 v2/engine/{src => }/boehm_gc/include/gc_cpp.h | 0 v2/engine/{src => }/boehm_gc/include/gc_gcj.h | 0 v2/engine/{src => }/boehm_gc/include/gc_inline.h | 0 v2/engine/{src => }/boehm_gc/include/gc_mark.h | 0 .../boehm_gc/include/gc_pthread_redirects.h | 0 v2/engine/{src => }/boehm_gc/include/gc_tiny_fl.h | 0 v2/engine/{src => }/boehm_gc/include/gc_typed.h | 0 v2/engine/{src => }/boehm_gc/include/include.am | 0 v2/engine/{src => }/boehm_gc/include/javaxfc.h | 0 .../{src => }/boehm_gc/include/leak_detector.h | 0 .../{src => }/boehm_gc/include/new_gc_alloc.h | 0 .../{src => }/boehm_gc/include/private/cord_pos.h | 0 .../boehm_gc/include/private/darwin_semaphore.h | 0 .../boehm_gc/include/private/darwin_stop_world.h | 0 .../{src => }/boehm_gc/include/private/dbg_mlc.h | 0 .../{src => }/boehm_gc/include/private/gc_hdrs.h | 0 .../{src => }/boehm_gc/include/private/gc_locks.h | 0 .../{src => }/boehm_gc/include/private/gc_pmark.h | 0 .../{src => }/boehm_gc/include/private/gc_priv.h | 0 .../{src => }/boehm_gc/include/private/gcconfig.h | 0 .../{src => }/boehm_gc/include/private/msvc_dbg.h | 0 .../boehm_gc/include/private/pthread_stop_world.h | 0 .../boehm_gc/include/private/pthread_support.h | 0 .../{src => }/boehm_gc/include/private/specific.h | 0 .../boehm_gc/include/private/thread_local_alloc.h | 0 .../{src => }/boehm_gc/include/weakpointer.h | 0 v2/engine/{src => }/boehm_gc/install-sh | 0 v2/engine/{src => }/boehm_gc/libtool.m4 | 0 v2/engine/{src => }/boehm_gc/ltmain.sh | 0 v2/engine/{src => }/boehm_gc/mach_dep.c | 0 v2/engine/{src => }/boehm_gc/malloc.c | 0 v2/engine/{src => }/boehm_gc/mallocx.c | 0 v2/engine/{src => }/boehm_gc/mark.c | 0 v2/engine/{src => }/boehm_gc/mark_rts.c | 0 v2/engine/{src => }/boehm_gc/mips_sgi_mach_dep.s | 0 .../{src => }/boehm_gc/mips_ultrix_mach_dep.s | 0 v2/engine/{src => }/boehm_gc/misc.c | 0 v2/engine/{src => }/boehm_gc/missing | 0 v2/engine/{src => }/boehm_gc/mkinstalldirs | 0 v2/engine/{src => }/boehm_gc/msvc_dbg.c | 0 v2/engine/{src => }/boehm_gc/new_hblk.c | 0 v2/engine/{src => }/boehm_gc/obj_map.c | 0 v2/engine/{src => }/boehm_gc/os_dep.c | 0 v2/engine/{src => }/boehm_gc/pcr_interface.c | 0 v2/engine/{src => }/boehm_gc/pthread_stop_world.c | 0 v2/engine/{src => }/boehm_gc/pthread_support.c | 0 v2/engine/{src => }/boehm_gc/ptr_chck.c | 0 v2/engine/{src => }/boehm_gc/real_malloc.c | 0 v2/engine/{src => }/boehm_gc/reclaim.c | 0 v2/engine/{src => }/boehm_gc/rs6000_mach_dep.s | 0 v2/engine/{src => }/boehm_gc/setjmp_t.c | 0 v2/engine/{src => }/boehm_gc/sparc_mach_dep.S | 0 .../{src => }/boehm_gc/sparc_netbsd_mach_dep.s | 0 .../{src => }/boehm_gc/sparc_sunos4_mach_dep.s | 0 v2/engine/{src => }/boehm_gc/specific.c | 0 v2/engine/{src => }/boehm_gc/stubborn.c | 0 v2/engine/{src => }/boehm_gc/tests/leak_test.c | 0 v2/engine/{src => }/boehm_gc/tests/middle.c | 0 v2/engine/{src => }/boehm_gc/tests/test.c | 0 v2/engine/{src => }/boehm_gc/tests/test_cpp.cc | 0 v2/engine/{src => }/boehm_gc/tests/tests.am | 0 .../{src => }/boehm_gc/tests/thread_leak_test.c | 0 v2/engine/{src => }/boehm_gc/thread_local_alloc.c | 0 v2/engine/{src => }/boehm_gc/threadlibs.c | 0 v2/engine/{src => }/boehm_gc/typd_mlc.c | 0 v2/engine/{src => }/boehm_gc/version.h | 0 v2/engine/{src => }/boehm_gc/win32_threads.c | 0 v2/engine/{src => }/boost-jam.spec | 0 v2/engine/{src => }/build.bat | 0 v2/engine/{src => }/build.jam | 0 v2/engine/{src => }/build.sh | 0 v2/engine/{src => }/build_vms.com | 0 v2/engine/{src => }/builtins.c | 0 v2/engine/{src => }/builtins.h | 0 v2/engine/{src => }/bump_version.py | 0 v2/engine/{src => }/class.c | 0 v2/engine/{src => }/class.h | 0 v2/engine/{src => }/command.c | 0 v2/engine/{src => }/command.h | 0 v2/engine/{src => }/compile.c | 0 v2/engine/{src => }/compile.h | 0 v2/engine/{src => }/debian/changelog | 0 v2/engine/{src => }/debian/control | 0 v2/engine/{src => }/debian/copyright | 0 v2/engine/{src => }/debian/jam.man.sgml | 0 v2/engine/{src => }/debian/rules | 0 v2/engine/{src => }/debug.c | 0 v2/engine/{src => }/debug.h | 0 v2/engine/{src => }/execcmd.h | 0 v2/engine/{src => }/execmac.c | 0 v2/engine/{src => }/execnt.c | 0 v2/engine/{src => }/execunix.c | 0 v2/engine/{src => }/execvms.c | 0 v2/engine/{src => }/expand.c | 0 v2/engine/{src => }/expand.h | 0 v2/engine/{src => }/filemac.c | 0 v2/engine/{src => }/filent.c | 0 v2/engine/{src => }/fileos2.c | 0 v2/engine/{src => }/filesys.c | 0 v2/engine/{src => }/filesys.h | 0 v2/engine/{src => }/fileunix.c | 0 v2/engine/{src => }/filevms.c | 0 v2/engine/{src => }/frames.c | 0 v2/engine/{src => }/frames.h | 0 v2/engine/{src => }/glob.c | 0 v2/engine/{src => }/hash.c | 0 v2/engine/{src => }/hash.h | 0 v2/engine/{src => }/hcache.c | 0 v2/engine/{src => }/hcache.h | 0 v2/engine/{src => }/hdrmacro.c | 0 v2/engine/{src => }/hdrmacro.h | 0 v2/engine/{src => }/headers.c | 0 v2/engine/{src => }/headers.h | 0 v2/engine/{src => }/jam.c | 0 v2/engine/{src => }/jam.h | 0 v2/engine/{src => }/jambase.c | 0 v2/engine/{src => }/jambase.h | 0 v2/engine/{src => }/jamgram.c | 0 v2/engine/{src => }/jamgram.h | 0 v2/engine/{src => }/jamgram.y | 0 v2/engine/{src => }/jamgram.yy | 0 v2/engine/{src => }/jamgramtab.h | 0 v2/engine/{src => }/lists.c | 0 v2/engine/{src => }/lists.h | 0 v2/engine/{src => }/make.c | 0 v2/engine/{src => }/make.h | 0 v2/engine/{src => }/make1.c | 0 v2/engine/{src => }/md5.c | 0 v2/engine/{src => }/md5.h | 0 v2/engine/{src => }/mem.c | 0 v2/engine/{src => }/mem.h | 0 v2/engine/{src => }/mkjambase.c | 0 v2/engine/{src => }/modules.c | 0 v2/engine/{src => }/modules.h | 0 v2/engine/{src => }/modules/order.c | 0 v2/engine/{src => }/modules/path.c | 0 v2/engine/{src => }/modules/property-set.c | 0 v2/engine/{src => }/modules/readme.txt | 0 v2/engine/{src => }/modules/regex.c | 0 v2/engine/{src => }/modules/sequence.c | 0 v2/engine/{src => }/modules/set.c | 0 v2/engine/{src => }/native.c | 0 v2/engine/{src => }/native.h | 0 v2/engine/{src => }/newstr.c | 0 v2/engine/{src => }/newstr.h | 0 v2/engine/{src => }/option.c | 0 v2/engine/{src => }/option.h | 0 v2/engine/{src => }/output.c | 0 v2/engine/{src => }/output.h | 0 v2/engine/{src => }/parse.c | 0 v2/engine/{src => }/parse.h | 0 v2/engine/{src => }/patchlevel.h | 0 v2/engine/{src => }/pathmac.c | 0 v2/engine/{src => }/pathsys.h | 0 v2/engine/{src => }/pathunix.c | 0 v2/engine/{src => }/pathvms.c | 0 v2/engine/{src => }/pwd.c | 0 v2/engine/{src => }/pwd.h | 0 v2/engine/{src => }/regexp.c | 0 v2/engine/{src => }/regexp.h | 0 v2/engine/{src => }/rules.c | 0 v2/engine/{src => }/rules.h | 0 v2/engine/{src => }/scan.c | 0 v2/engine/{src => }/scan.h | 0 v2/engine/{src => }/search.c | 0 v2/engine/{src => }/search.h | 0 v2/engine/{src => }/strings.c | 0 v2/engine/{src => }/strings.h | 0 v2/engine/{src => }/subst.c | 0 v2/engine/{src => }/timestamp.c | 0 v2/engine/{src => }/timestamp.h | 0 v2/engine/{src => }/variable.c | 0 v2/engine/{src => }/variable.h | 0 v2/engine/{src => }/w32_getreg.c | 0 v2/engine/{src => }/yyacc.c | 0 292 files changed, 12 insertions(+), 12 deletions(-) rename v2/engine/{src => }/Jambase (100%) rename v2/engine/{src => }/boehm_gc/AmigaOS.c (100%) rename v2/engine/{src => }/boehm_gc/BCC_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/ChangeLog (100%) rename v2/engine/{src => }/boehm_gc/EMX_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/MacOS.c (100%) rename v2/engine/{src => }/boehm_gc/MacProjects.sit.hqx (100%) rename v2/engine/{src => }/boehm_gc/Mac_files/MacOS_Test_config.h (100%) rename v2/engine/{src => }/boehm_gc/Mac_files/MacOS_config.h (100%) rename v2/engine/{src => }/boehm_gc/Mac_files/dataend.c (100%) rename v2/engine/{src => }/boehm_gc/Mac_files/datastart.c (100%) rename v2/engine/{src => }/boehm_gc/Makefile.DLLs (100%) rename v2/engine/{src => }/boehm_gc/Makefile.am (100%) rename v2/engine/{src => }/boehm_gc/Makefile.direct (100%) rename v2/engine/{src => }/boehm_gc/Makefile.dj (100%) rename v2/engine/{src => }/boehm_gc/Makefile.in (100%) rename v2/engine/{src => }/boehm_gc/NT_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/NT_STATIC_THREADS_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/NT_THREADS_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/OS2_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/PCR-Makefile (100%) rename v2/engine/{src => }/boehm_gc/README.QUICK (100%) rename v2/engine/{src => }/boehm_gc/SMakefile.amiga (100%) rename v2/engine/{src => }/boehm_gc/WCC_MAKEFILE (100%) rename v2/engine/{src => }/boehm_gc/acinclude.m4 (100%) rename v2/engine/{src => }/boehm_gc/aclocal.m4 (100%) rename v2/engine/{src => }/boehm_gc/add_gc_prefix.c (100%) rename v2/engine/{src => }/boehm_gc/allchblk.c (100%) rename v2/engine/{src => }/boehm_gc/alloc.c (100%) rename v2/engine/{src => }/boehm_gc/alpha_mach_dep.S (100%) rename v2/engine/{src => }/boehm_gc/backgraph.c (100%) rename v2/engine/{src => }/boehm_gc/bdw-gc.pc (100%) rename v2/engine/{src => }/boehm_gc/bdw-gc.pc.in (100%) rename v2/engine/{src => }/boehm_gc/blacklst.c (100%) rename v2/engine/{src => }/boehm_gc/callprocs (100%) rename v2/engine/{src => }/boehm_gc/checksums.c (100%) rename v2/engine/{src => }/boehm_gc/compile (100%) rename v2/engine/{src => }/boehm_gc/config.guess (100%) rename v2/engine/{src => }/boehm_gc/config.sub (100%) rename v2/engine/{src => }/boehm_gc/configure (100%) rename v2/engine/{src => }/boehm_gc/configure.ac (100%) rename v2/engine/{src => }/boehm_gc/configure.host (100%) rename v2/engine/{src => }/boehm_gc/configure_atomic_ops.sh (100%) rename v2/engine/{src => }/boehm_gc/cord/cord.am (100%) rename v2/engine/{src => }/boehm_gc/cord/cordbscs.c (100%) rename v2/engine/{src => }/boehm_gc/cord/cordprnt.c (100%) rename v2/engine/{src => }/boehm_gc/cord/cordtest.c (100%) rename v2/engine/{src => }/boehm_gc/cord/cordxtra.c (100%) rename v2/engine/{src => }/boehm_gc/cord/de.c (100%) rename v2/engine/{src => }/boehm_gc/cord/de_cmds.h (100%) rename v2/engine/{src => }/boehm_gc/cord/de_win.ICO (100%) rename v2/engine/{src => }/boehm_gc/cord/de_win.RC (100%) rename v2/engine/{src => }/boehm_gc/cord/de_win.c (100%) rename v2/engine/{src => }/boehm_gc/cord/de_win.h (100%) rename v2/engine/{src => }/boehm_gc/darwin_stop_world.c (100%) rename v2/engine/{src => }/boehm_gc/dbg_mlc.c (100%) rename v2/engine/{src => }/boehm_gc/depcomp (100%) rename v2/engine/{src => }/boehm_gc/digimars.mak (100%) rename v2/engine/{src => }/boehm_gc/doc/README (100%) rename v2/engine/{src => }/boehm_gc/doc/README.DGUX386 (100%) rename v2/engine/{src => }/boehm_gc/doc/README.Mac (100%) rename v2/engine/{src => }/boehm_gc/doc/README.MacOSX (100%) rename v2/engine/{src => }/boehm_gc/doc/README.OS2 (100%) rename v2/engine/{src => }/boehm_gc/doc/README.amiga (100%) rename v2/engine/{src => }/boehm_gc/doc/README.arm.cross (100%) rename v2/engine/{src => }/boehm_gc/doc/README.autoconf (100%) rename v2/engine/{src => }/boehm_gc/doc/README.changes (100%) rename v2/engine/{src => }/boehm_gc/doc/README.contributors (100%) rename v2/engine/{src => }/boehm_gc/doc/README.cords (100%) rename v2/engine/{src => }/boehm_gc/doc/README.darwin (100%) rename v2/engine/{src => }/boehm_gc/doc/README.dj (100%) rename v2/engine/{src => }/boehm_gc/doc/README.environment (100%) rename v2/engine/{src => }/boehm_gc/doc/README.ews4800 (100%) rename v2/engine/{src => }/boehm_gc/doc/README.hp (100%) rename v2/engine/{src => }/boehm_gc/doc/README.linux (100%) rename v2/engine/{src => }/boehm_gc/doc/README.macros (100%) rename v2/engine/{src => }/boehm_gc/doc/README.rs6000 (100%) rename v2/engine/{src => }/boehm_gc/doc/README.sgi (100%) rename v2/engine/{src => }/boehm_gc/doc/README.solaris2 (100%) rename v2/engine/{src => }/boehm_gc/doc/README.uts (100%) rename v2/engine/{src => }/boehm_gc/doc/README.win32 (100%) rename v2/engine/{src => }/boehm_gc/doc/README.win64 (100%) rename v2/engine/{src => }/boehm_gc/doc/barrett_diagram (100%) rename v2/engine/{src => }/boehm_gc/doc/debugging.html (100%) rename v2/engine/{src => }/boehm_gc/doc/doc.am (100%) rename v2/engine/{src => }/boehm_gc/doc/gc.man (100%) rename v2/engine/{src => }/boehm_gc/doc/gcdescr.html (100%) rename v2/engine/{src => }/boehm_gc/doc/gcinterface.html (100%) rename v2/engine/{src => }/boehm_gc/doc/leak.html (100%) rename v2/engine/{src => }/boehm_gc/doc/overview.html (100%) rename v2/engine/{src => }/boehm_gc/doc/porting.html (100%) rename v2/engine/{src => }/boehm_gc/doc/scale.html (100%) rename v2/engine/{src => }/boehm_gc/doc/simple_example.html (100%) rename v2/engine/{src => }/boehm_gc/doc/tree.html (100%) rename v2/engine/{src => }/boehm_gc/dyn_load.c (100%) rename v2/engine/{src => }/boehm_gc/finalize.c (100%) rename v2/engine/{src => }/boehm_gc/gc.mak (100%) rename v2/engine/{src => }/boehm_gc/gc_cpp.cc (100%) rename v2/engine/{src => }/boehm_gc/gc_cpp.cpp (100%) rename v2/engine/{src => }/boehm_gc/gc_dlopen.c (100%) rename v2/engine/{src => }/boehm_gc/gcj_mlc.c (100%) rename v2/engine/{src => }/boehm_gc/gcname.c (100%) rename v2/engine/{src => }/boehm_gc/headers.c (100%) rename v2/engine/{src => }/boehm_gc/hpux_test_and_clear.s (100%) rename v2/engine/{src => }/boehm_gc/ia64_save_regs_in_stack.s (100%) rename v2/engine/{src => }/boehm_gc/if_mach.c (100%) rename v2/engine/{src => }/boehm_gc/if_not_there.c (100%) rename v2/engine/{src => }/boehm_gc/include/cord.h (100%) rename v2/engine/{src => }/boehm_gc/include/ec.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_allocator.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_amiga_redirects.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_backptr.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_config_macros.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_cpp.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_gcj.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_inline.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_mark.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_pthread_redirects.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_tiny_fl.h (100%) rename v2/engine/{src => }/boehm_gc/include/gc_typed.h (100%) rename v2/engine/{src => }/boehm_gc/include/include.am (100%) rename v2/engine/{src => }/boehm_gc/include/javaxfc.h (100%) rename v2/engine/{src => }/boehm_gc/include/leak_detector.h (100%) rename v2/engine/{src => }/boehm_gc/include/new_gc_alloc.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/cord_pos.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/darwin_semaphore.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/darwin_stop_world.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/dbg_mlc.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/gc_hdrs.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/gc_locks.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/gc_pmark.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/gc_priv.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/gcconfig.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/msvc_dbg.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/pthread_stop_world.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/pthread_support.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/specific.h (100%) rename v2/engine/{src => }/boehm_gc/include/private/thread_local_alloc.h (100%) rename v2/engine/{src => }/boehm_gc/include/weakpointer.h (100%) rename v2/engine/{src => }/boehm_gc/install-sh (100%) rename v2/engine/{src => }/boehm_gc/libtool.m4 (100%) rename v2/engine/{src => }/boehm_gc/ltmain.sh (100%) rename v2/engine/{src => }/boehm_gc/mach_dep.c (100%) rename v2/engine/{src => }/boehm_gc/malloc.c (100%) rename v2/engine/{src => }/boehm_gc/mallocx.c (100%) rename v2/engine/{src => }/boehm_gc/mark.c (100%) rename v2/engine/{src => }/boehm_gc/mark_rts.c (100%) rename v2/engine/{src => }/boehm_gc/mips_sgi_mach_dep.s (100%) rename v2/engine/{src => }/boehm_gc/mips_ultrix_mach_dep.s (100%) rename v2/engine/{src => }/boehm_gc/misc.c (100%) rename v2/engine/{src => }/boehm_gc/missing (100%) rename v2/engine/{src => }/boehm_gc/mkinstalldirs (100%) rename v2/engine/{src => }/boehm_gc/msvc_dbg.c (100%) rename v2/engine/{src => }/boehm_gc/new_hblk.c (100%) rename v2/engine/{src => }/boehm_gc/obj_map.c (100%) rename v2/engine/{src => }/boehm_gc/os_dep.c (100%) rename v2/engine/{src => }/boehm_gc/pcr_interface.c (100%) rename v2/engine/{src => }/boehm_gc/pthread_stop_world.c (100%) rename v2/engine/{src => }/boehm_gc/pthread_support.c (100%) rename v2/engine/{src => }/boehm_gc/ptr_chck.c (100%) rename v2/engine/{src => }/boehm_gc/real_malloc.c (100%) rename v2/engine/{src => }/boehm_gc/reclaim.c (100%) rename v2/engine/{src => }/boehm_gc/rs6000_mach_dep.s (100%) rename v2/engine/{src => }/boehm_gc/setjmp_t.c (100%) rename v2/engine/{src => }/boehm_gc/sparc_mach_dep.S (100%) rename v2/engine/{src => }/boehm_gc/sparc_netbsd_mach_dep.s (100%) rename v2/engine/{src => }/boehm_gc/sparc_sunos4_mach_dep.s (100%) rename v2/engine/{src => }/boehm_gc/specific.c (100%) rename v2/engine/{src => }/boehm_gc/stubborn.c (100%) rename v2/engine/{src => }/boehm_gc/tests/leak_test.c (100%) rename v2/engine/{src => }/boehm_gc/tests/middle.c (100%) rename v2/engine/{src => }/boehm_gc/tests/test.c (100%) rename v2/engine/{src => }/boehm_gc/tests/test_cpp.cc (100%) rename v2/engine/{src => }/boehm_gc/tests/tests.am (100%) rename v2/engine/{src => }/boehm_gc/tests/thread_leak_test.c (100%) rename v2/engine/{src => }/boehm_gc/thread_local_alloc.c (100%) rename v2/engine/{src => }/boehm_gc/threadlibs.c (100%) rename v2/engine/{src => }/boehm_gc/typd_mlc.c (100%) rename v2/engine/{src => }/boehm_gc/version.h (100%) rename v2/engine/{src => }/boehm_gc/win32_threads.c (100%) rename v2/engine/{src => }/boost-jam.spec (100%) rename v2/engine/{src => }/build.bat (100%) rename v2/engine/{src => }/build.jam (100%) rename v2/engine/{src => }/build.sh (100%) rename v2/engine/{src => }/build_vms.com (100%) rename v2/engine/{src => }/builtins.c (100%) rename v2/engine/{src => }/builtins.h (100%) rename v2/engine/{src => }/bump_version.py (100%) rename v2/engine/{src => }/class.c (100%) rename v2/engine/{src => }/class.h (100%) rename v2/engine/{src => }/command.c (100%) rename v2/engine/{src => }/command.h (100%) rename v2/engine/{src => }/compile.c (100%) rename v2/engine/{src => }/compile.h (100%) rename v2/engine/{src => }/debian/changelog (100%) rename v2/engine/{src => }/debian/control (100%) rename v2/engine/{src => }/debian/copyright (100%) rename v2/engine/{src => }/debian/jam.man.sgml (100%) rename v2/engine/{src => }/debian/rules (100%) rename v2/engine/{src => }/debug.c (100%) rename v2/engine/{src => }/debug.h (100%) rename v2/engine/{src => }/execcmd.h (100%) rename v2/engine/{src => }/execmac.c (100%) rename v2/engine/{src => }/execnt.c (100%) rename v2/engine/{src => }/execunix.c (100%) rename v2/engine/{src => }/execvms.c (100%) rename v2/engine/{src => }/expand.c (100%) rename v2/engine/{src => }/expand.h (100%) rename v2/engine/{src => }/filemac.c (100%) rename v2/engine/{src => }/filent.c (100%) rename v2/engine/{src => }/fileos2.c (100%) rename v2/engine/{src => }/filesys.c (100%) rename v2/engine/{src => }/filesys.h (100%) rename v2/engine/{src => }/fileunix.c (100%) rename v2/engine/{src => }/filevms.c (100%) rename v2/engine/{src => }/frames.c (100%) rename v2/engine/{src => }/frames.h (100%) rename v2/engine/{src => }/glob.c (100%) rename v2/engine/{src => }/hash.c (100%) rename v2/engine/{src => }/hash.h (100%) rename v2/engine/{src => }/hcache.c (100%) rename v2/engine/{src => }/hcache.h (100%) rename v2/engine/{src => }/hdrmacro.c (100%) rename v2/engine/{src => }/hdrmacro.h (100%) rename v2/engine/{src => }/headers.c (100%) rename v2/engine/{src => }/headers.h (100%) rename v2/engine/{src => }/jam.c (100%) rename v2/engine/{src => }/jam.h (100%) rename v2/engine/{src => }/jambase.c (100%) rename v2/engine/{src => }/jambase.h (100%) rename v2/engine/{src => }/jamgram.c (100%) rename v2/engine/{src => }/jamgram.h (100%) rename v2/engine/{src => }/jamgram.y (100%) rename v2/engine/{src => }/jamgram.yy (100%) rename v2/engine/{src => }/jamgramtab.h (100%) rename v2/engine/{src => }/lists.c (100%) rename v2/engine/{src => }/lists.h (100%) rename v2/engine/{src => }/make.c (100%) rename v2/engine/{src => }/make.h (100%) rename v2/engine/{src => }/make1.c (100%) rename v2/engine/{src => }/md5.c (100%) rename v2/engine/{src => }/md5.h (100%) rename v2/engine/{src => }/mem.c (100%) rename v2/engine/{src => }/mem.h (100%) rename v2/engine/{src => }/mkjambase.c (100%) rename v2/engine/{src => }/modules.c (100%) rename v2/engine/{src => }/modules.h (100%) rename v2/engine/{src => }/modules/order.c (100%) rename v2/engine/{src => }/modules/path.c (100%) rename v2/engine/{src => }/modules/property-set.c (100%) rename v2/engine/{src => }/modules/readme.txt (100%) rename v2/engine/{src => }/modules/regex.c (100%) rename v2/engine/{src => }/modules/sequence.c (100%) rename v2/engine/{src => }/modules/set.c (100%) rename v2/engine/{src => }/native.c (100%) rename v2/engine/{src => }/native.h (100%) rename v2/engine/{src => }/newstr.c (100%) rename v2/engine/{src => }/newstr.h (100%) rename v2/engine/{src => }/option.c (100%) rename v2/engine/{src => }/option.h (100%) rename v2/engine/{src => }/output.c (100%) rename v2/engine/{src => }/output.h (100%) rename v2/engine/{src => }/parse.c (100%) rename v2/engine/{src => }/parse.h (100%) rename v2/engine/{src => }/patchlevel.h (100%) rename v2/engine/{src => }/pathmac.c (100%) rename v2/engine/{src => }/pathsys.h (100%) rename v2/engine/{src => }/pathunix.c (100%) rename v2/engine/{src => }/pathvms.c (100%) rename v2/engine/{src => }/pwd.c (100%) rename v2/engine/{src => }/pwd.h (100%) rename v2/engine/{src => }/regexp.c (100%) rename v2/engine/{src => }/regexp.h (100%) rename v2/engine/{src => }/rules.c (100%) rename v2/engine/{src => }/rules.h (100%) rename v2/engine/{src => }/scan.c (100%) rename v2/engine/{src => }/scan.h (100%) rename v2/engine/{src => }/search.c (100%) rename v2/engine/{src => }/search.h (100%) rename v2/engine/{src => }/strings.c (100%) rename v2/engine/{src => }/strings.h (100%) rename v2/engine/{src => }/subst.c (100%) rename v2/engine/{src => }/timestamp.c (100%) rename v2/engine/{src => }/timestamp.h (100%) rename v2/engine/{src => }/variable.c (100%) rename v2/engine/{src => }/variable.h (100%) rename v2/engine/{src => }/w32_getreg.c (100%) rename v2/engine/{src => }/yyacc.c (100%) diff --git a/v2/bootstrap.bat b/v2/bootstrap.bat index 3fa2b199d..f34b07b45 100644 --- a/v2/bootstrap.bat +++ b/v2/bootstrap.bat @@ -6,20 +6,20 @@ 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) ECHO Bootstrapping the build engine -if exist ".\engine\src\bin.ntx86\bjam.exe" del engine\src\bin.ntx86\bjam.exe -if exist ".\engine\src\bin.ntx86_64\bjam.exe" del engine\src\bin.ntx86_64\bjam.exe -cd engine\src +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 @ECHO OFF cd ..\.. -if exist ".\engine\src\bin.ntx86\bjam.exe" ( - copy .\engine\src\bin.ntx86\bjam.exe . > nul +if exist ".\engine\bin.ntx86\bjam.exe" ( + copy .\engine\bin.ntx86\bjam.exe . > nul goto :bjam_built) -if exist ".\engine\src\bin.ntx86_64\bjam.exe" ( - copy .\engine\src\bin.ntx86_64\bjam.exe . > nul +if exist ".\engine\bin.ntx86_64\bjam.exe" ( + copy .\engine\bin.ntx86_64\bjam.exe . > nul goto :bjam_built) goto :bjam_failure diff --git a/v2/bootstrap.sh b/v2/bootstrap.sh index 3b681004c..38bfbdc75 100755 --- a/v2/bootstrap.sh +++ b/v2/bootstrap.sh @@ -55,7 +55,7 @@ my_dir="." # Determine the toolset, if not already decided if test "x$TOOLSET" = x; then - guessed_toolset=`$my_dir/engine/src/build.sh --guess-toolset` + guessed_toolset=`$my_dir/engine/build.sh --guess-toolset` case $guessed_toolset in acc | darwin | gcc | como | mipspro | pathscale | pgi | qcc | vacpp ) TOOLSET=$guessed_toolset @@ -96,7 +96,7 @@ rm -f config.log if test "x$BJAM" = x; then echo -n "Bootstrapping the build engine with toolset $TOOLSET... " pwd=`pwd` - (cd "$my_dir/engine/src" && ./build.sh "$TOOLSET") > bootstrap.log 2>&1 + (cd "$my_dir/engine" && ./build.sh "$TOOLSET") > bootstrap.log 2>&1 if [ $? -ne 0 ]; then echo echo "Failed to bootstrap the build engine" @@ -104,9 +104,9 @@ if test "x$BJAM" = x; then exit 1 fi cd "$pwd" - arch=`cd $my_dir/engine/src && ./bootstrap/jam0 -d0 -f build.jam --toolset=$TOOLSET --toolset-root= --show-locate-target && cd ..` - BJAM="$my_dir/engine/src/$arch/bjam" - echo "engine/src/$arch/bjam" + arch=`cd $my_dir/engine && ./bootstrap/jam0 -d0 -f build.jam --toolset=$TOOLSET --toolset-root= --show-locate-target && cd ..` + BJAM="$my_dir/engine/$arch/bjam" + echo "engine/$arch/bjam" cp "$BJAM" . fi diff --git a/v2/engine/src/Jambase b/v2/engine/Jambase similarity index 100% rename from v2/engine/src/Jambase rename to v2/engine/Jambase diff --git a/v2/engine/src/boehm_gc/AmigaOS.c b/v2/engine/boehm_gc/AmigaOS.c similarity index 100% rename from v2/engine/src/boehm_gc/AmigaOS.c rename to v2/engine/boehm_gc/AmigaOS.c diff --git a/v2/engine/src/boehm_gc/BCC_MAKEFILE b/v2/engine/boehm_gc/BCC_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/BCC_MAKEFILE rename to v2/engine/boehm_gc/BCC_MAKEFILE diff --git a/v2/engine/src/boehm_gc/ChangeLog b/v2/engine/boehm_gc/ChangeLog similarity index 100% rename from v2/engine/src/boehm_gc/ChangeLog rename to v2/engine/boehm_gc/ChangeLog diff --git a/v2/engine/src/boehm_gc/EMX_MAKEFILE b/v2/engine/boehm_gc/EMX_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/EMX_MAKEFILE rename to v2/engine/boehm_gc/EMX_MAKEFILE diff --git a/v2/engine/src/boehm_gc/MacOS.c b/v2/engine/boehm_gc/MacOS.c similarity index 100% rename from v2/engine/src/boehm_gc/MacOS.c rename to v2/engine/boehm_gc/MacOS.c diff --git a/v2/engine/src/boehm_gc/MacProjects.sit.hqx b/v2/engine/boehm_gc/MacProjects.sit.hqx similarity index 100% rename from v2/engine/src/boehm_gc/MacProjects.sit.hqx rename to v2/engine/boehm_gc/MacProjects.sit.hqx diff --git a/v2/engine/src/boehm_gc/Mac_files/MacOS_Test_config.h b/v2/engine/boehm_gc/Mac_files/MacOS_Test_config.h similarity index 100% rename from v2/engine/src/boehm_gc/Mac_files/MacOS_Test_config.h rename to v2/engine/boehm_gc/Mac_files/MacOS_Test_config.h diff --git a/v2/engine/src/boehm_gc/Mac_files/MacOS_config.h b/v2/engine/boehm_gc/Mac_files/MacOS_config.h similarity index 100% rename from v2/engine/src/boehm_gc/Mac_files/MacOS_config.h rename to v2/engine/boehm_gc/Mac_files/MacOS_config.h diff --git a/v2/engine/src/boehm_gc/Mac_files/dataend.c b/v2/engine/boehm_gc/Mac_files/dataend.c similarity index 100% rename from v2/engine/src/boehm_gc/Mac_files/dataend.c rename to v2/engine/boehm_gc/Mac_files/dataend.c diff --git a/v2/engine/src/boehm_gc/Mac_files/datastart.c b/v2/engine/boehm_gc/Mac_files/datastart.c similarity index 100% rename from v2/engine/src/boehm_gc/Mac_files/datastart.c rename to v2/engine/boehm_gc/Mac_files/datastart.c diff --git a/v2/engine/src/boehm_gc/Makefile.DLLs b/v2/engine/boehm_gc/Makefile.DLLs similarity index 100% rename from v2/engine/src/boehm_gc/Makefile.DLLs rename to v2/engine/boehm_gc/Makefile.DLLs diff --git a/v2/engine/src/boehm_gc/Makefile.am b/v2/engine/boehm_gc/Makefile.am similarity index 100% rename from v2/engine/src/boehm_gc/Makefile.am rename to v2/engine/boehm_gc/Makefile.am diff --git a/v2/engine/src/boehm_gc/Makefile.direct b/v2/engine/boehm_gc/Makefile.direct similarity index 100% rename from v2/engine/src/boehm_gc/Makefile.direct rename to v2/engine/boehm_gc/Makefile.direct diff --git a/v2/engine/src/boehm_gc/Makefile.dj b/v2/engine/boehm_gc/Makefile.dj similarity index 100% rename from v2/engine/src/boehm_gc/Makefile.dj rename to v2/engine/boehm_gc/Makefile.dj diff --git a/v2/engine/src/boehm_gc/Makefile.in b/v2/engine/boehm_gc/Makefile.in similarity index 100% rename from v2/engine/src/boehm_gc/Makefile.in rename to v2/engine/boehm_gc/Makefile.in diff --git a/v2/engine/src/boehm_gc/NT_MAKEFILE b/v2/engine/boehm_gc/NT_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/NT_MAKEFILE rename to v2/engine/boehm_gc/NT_MAKEFILE diff --git a/v2/engine/src/boehm_gc/NT_STATIC_THREADS_MAKEFILE b/v2/engine/boehm_gc/NT_STATIC_THREADS_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/NT_STATIC_THREADS_MAKEFILE rename to v2/engine/boehm_gc/NT_STATIC_THREADS_MAKEFILE diff --git a/v2/engine/src/boehm_gc/NT_THREADS_MAKEFILE b/v2/engine/boehm_gc/NT_THREADS_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/NT_THREADS_MAKEFILE rename to v2/engine/boehm_gc/NT_THREADS_MAKEFILE diff --git a/v2/engine/src/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE b/v2/engine/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE rename to v2/engine/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE diff --git a/v2/engine/src/boehm_gc/OS2_MAKEFILE b/v2/engine/boehm_gc/OS2_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/OS2_MAKEFILE rename to v2/engine/boehm_gc/OS2_MAKEFILE diff --git a/v2/engine/src/boehm_gc/PCR-Makefile b/v2/engine/boehm_gc/PCR-Makefile similarity index 100% rename from v2/engine/src/boehm_gc/PCR-Makefile rename to v2/engine/boehm_gc/PCR-Makefile diff --git a/v2/engine/src/boehm_gc/README.QUICK b/v2/engine/boehm_gc/README.QUICK similarity index 100% rename from v2/engine/src/boehm_gc/README.QUICK rename to v2/engine/boehm_gc/README.QUICK diff --git a/v2/engine/src/boehm_gc/SMakefile.amiga b/v2/engine/boehm_gc/SMakefile.amiga similarity index 100% rename from v2/engine/src/boehm_gc/SMakefile.amiga rename to v2/engine/boehm_gc/SMakefile.amiga diff --git a/v2/engine/src/boehm_gc/WCC_MAKEFILE b/v2/engine/boehm_gc/WCC_MAKEFILE similarity index 100% rename from v2/engine/src/boehm_gc/WCC_MAKEFILE rename to v2/engine/boehm_gc/WCC_MAKEFILE diff --git a/v2/engine/src/boehm_gc/acinclude.m4 b/v2/engine/boehm_gc/acinclude.m4 similarity index 100% rename from v2/engine/src/boehm_gc/acinclude.m4 rename to v2/engine/boehm_gc/acinclude.m4 diff --git a/v2/engine/src/boehm_gc/aclocal.m4 b/v2/engine/boehm_gc/aclocal.m4 similarity index 100% rename from v2/engine/src/boehm_gc/aclocal.m4 rename to v2/engine/boehm_gc/aclocal.m4 diff --git a/v2/engine/src/boehm_gc/add_gc_prefix.c b/v2/engine/boehm_gc/add_gc_prefix.c similarity index 100% rename from v2/engine/src/boehm_gc/add_gc_prefix.c rename to v2/engine/boehm_gc/add_gc_prefix.c diff --git a/v2/engine/src/boehm_gc/allchblk.c b/v2/engine/boehm_gc/allchblk.c similarity index 100% rename from v2/engine/src/boehm_gc/allchblk.c rename to v2/engine/boehm_gc/allchblk.c diff --git a/v2/engine/src/boehm_gc/alloc.c b/v2/engine/boehm_gc/alloc.c similarity index 100% rename from v2/engine/src/boehm_gc/alloc.c rename to v2/engine/boehm_gc/alloc.c diff --git a/v2/engine/src/boehm_gc/alpha_mach_dep.S b/v2/engine/boehm_gc/alpha_mach_dep.S similarity index 100% rename from v2/engine/src/boehm_gc/alpha_mach_dep.S rename to v2/engine/boehm_gc/alpha_mach_dep.S diff --git a/v2/engine/src/boehm_gc/backgraph.c b/v2/engine/boehm_gc/backgraph.c similarity index 100% rename from v2/engine/src/boehm_gc/backgraph.c rename to v2/engine/boehm_gc/backgraph.c diff --git a/v2/engine/src/boehm_gc/bdw-gc.pc b/v2/engine/boehm_gc/bdw-gc.pc similarity index 100% rename from v2/engine/src/boehm_gc/bdw-gc.pc rename to v2/engine/boehm_gc/bdw-gc.pc diff --git a/v2/engine/src/boehm_gc/bdw-gc.pc.in b/v2/engine/boehm_gc/bdw-gc.pc.in similarity index 100% rename from v2/engine/src/boehm_gc/bdw-gc.pc.in rename to v2/engine/boehm_gc/bdw-gc.pc.in diff --git a/v2/engine/src/boehm_gc/blacklst.c b/v2/engine/boehm_gc/blacklst.c similarity index 100% rename from v2/engine/src/boehm_gc/blacklst.c rename to v2/engine/boehm_gc/blacklst.c diff --git a/v2/engine/src/boehm_gc/callprocs b/v2/engine/boehm_gc/callprocs similarity index 100% rename from v2/engine/src/boehm_gc/callprocs rename to v2/engine/boehm_gc/callprocs diff --git a/v2/engine/src/boehm_gc/checksums.c b/v2/engine/boehm_gc/checksums.c similarity index 100% rename from v2/engine/src/boehm_gc/checksums.c rename to v2/engine/boehm_gc/checksums.c diff --git a/v2/engine/src/boehm_gc/compile b/v2/engine/boehm_gc/compile similarity index 100% rename from v2/engine/src/boehm_gc/compile rename to v2/engine/boehm_gc/compile diff --git a/v2/engine/src/boehm_gc/config.guess b/v2/engine/boehm_gc/config.guess similarity index 100% rename from v2/engine/src/boehm_gc/config.guess rename to v2/engine/boehm_gc/config.guess diff --git a/v2/engine/src/boehm_gc/config.sub b/v2/engine/boehm_gc/config.sub similarity index 100% rename from v2/engine/src/boehm_gc/config.sub rename to v2/engine/boehm_gc/config.sub diff --git a/v2/engine/src/boehm_gc/configure b/v2/engine/boehm_gc/configure similarity index 100% rename from v2/engine/src/boehm_gc/configure rename to v2/engine/boehm_gc/configure diff --git a/v2/engine/src/boehm_gc/configure.ac b/v2/engine/boehm_gc/configure.ac similarity index 100% rename from v2/engine/src/boehm_gc/configure.ac rename to v2/engine/boehm_gc/configure.ac diff --git a/v2/engine/src/boehm_gc/configure.host b/v2/engine/boehm_gc/configure.host similarity index 100% rename from v2/engine/src/boehm_gc/configure.host rename to v2/engine/boehm_gc/configure.host diff --git a/v2/engine/src/boehm_gc/configure_atomic_ops.sh b/v2/engine/boehm_gc/configure_atomic_ops.sh similarity index 100% rename from v2/engine/src/boehm_gc/configure_atomic_ops.sh rename to v2/engine/boehm_gc/configure_atomic_ops.sh diff --git a/v2/engine/src/boehm_gc/cord/cord.am b/v2/engine/boehm_gc/cord/cord.am similarity index 100% rename from v2/engine/src/boehm_gc/cord/cord.am rename to v2/engine/boehm_gc/cord/cord.am diff --git a/v2/engine/src/boehm_gc/cord/cordbscs.c b/v2/engine/boehm_gc/cord/cordbscs.c similarity index 100% rename from v2/engine/src/boehm_gc/cord/cordbscs.c rename to v2/engine/boehm_gc/cord/cordbscs.c diff --git a/v2/engine/src/boehm_gc/cord/cordprnt.c b/v2/engine/boehm_gc/cord/cordprnt.c similarity index 100% rename from v2/engine/src/boehm_gc/cord/cordprnt.c rename to v2/engine/boehm_gc/cord/cordprnt.c diff --git a/v2/engine/src/boehm_gc/cord/cordtest.c b/v2/engine/boehm_gc/cord/cordtest.c similarity index 100% rename from v2/engine/src/boehm_gc/cord/cordtest.c rename to v2/engine/boehm_gc/cord/cordtest.c diff --git a/v2/engine/src/boehm_gc/cord/cordxtra.c b/v2/engine/boehm_gc/cord/cordxtra.c similarity index 100% rename from v2/engine/src/boehm_gc/cord/cordxtra.c rename to v2/engine/boehm_gc/cord/cordxtra.c diff --git a/v2/engine/src/boehm_gc/cord/de.c b/v2/engine/boehm_gc/cord/de.c similarity index 100% rename from v2/engine/src/boehm_gc/cord/de.c rename to v2/engine/boehm_gc/cord/de.c diff --git a/v2/engine/src/boehm_gc/cord/de_cmds.h b/v2/engine/boehm_gc/cord/de_cmds.h similarity index 100% rename from v2/engine/src/boehm_gc/cord/de_cmds.h rename to v2/engine/boehm_gc/cord/de_cmds.h diff --git a/v2/engine/src/boehm_gc/cord/de_win.ICO b/v2/engine/boehm_gc/cord/de_win.ICO similarity index 100% rename from v2/engine/src/boehm_gc/cord/de_win.ICO rename to v2/engine/boehm_gc/cord/de_win.ICO diff --git a/v2/engine/src/boehm_gc/cord/de_win.RC b/v2/engine/boehm_gc/cord/de_win.RC similarity index 100% rename from v2/engine/src/boehm_gc/cord/de_win.RC rename to v2/engine/boehm_gc/cord/de_win.RC diff --git a/v2/engine/src/boehm_gc/cord/de_win.c b/v2/engine/boehm_gc/cord/de_win.c similarity index 100% rename from v2/engine/src/boehm_gc/cord/de_win.c rename to v2/engine/boehm_gc/cord/de_win.c diff --git a/v2/engine/src/boehm_gc/cord/de_win.h b/v2/engine/boehm_gc/cord/de_win.h similarity index 100% rename from v2/engine/src/boehm_gc/cord/de_win.h rename to v2/engine/boehm_gc/cord/de_win.h diff --git a/v2/engine/src/boehm_gc/darwin_stop_world.c b/v2/engine/boehm_gc/darwin_stop_world.c similarity index 100% rename from v2/engine/src/boehm_gc/darwin_stop_world.c rename to v2/engine/boehm_gc/darwin_stop_world.c diff --git a/v2/engine/src/boehm_gc/dbg_mlc.c b/v2/engine/boehm_gc/dbg_mlc.c similarity index 100% rename from v2/engine/src/boehm_gc/dbg_mlc.c rename to v2/engine/boehm_gc/dbg_mlc.c diff --git a/v2/engine/src/boehm_gc/depcomp b/v2/engine/boehm_gc/depcomp similarity index 100% rename from v2/engine/src/boehm_gc/depcomp rename to v2/engine/boehm_gc/depcomp diff --git a/v2/engine/src/boehm_gc/digimars.mak b/v2/engine/boehm_gc/digimars.mak similarity index 100% rename from v2/engine/src/boehm_gc/digimars.mak rename to v2/engine/boehm_gc/digimars.mak diff --git a/v2/engine/src/boehm_gc/doc/README b/v2/engine/boehm_gc/doc/README similarity index 100% rename from v2/engine/src/boehm_gc/doc/README rename to v2/engine/boehm_gc/doc/README diff --git a/v2/engine/src/boehm_gc/doc/README.DGUX386 b/v2/engine/boehm_gc/doc/README.DGUX386 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.DGUX386 rename to v2/engine/boehm_gc/doc/README.DGUX386 diff --git a/v2/engine/src/boehm_gc/doc/README.Mac b/v2/engine/boehm_gc/doc/README.Mac similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.Mac rename to v2/engine/boehm_gc/doc/README.Mac diff --git a/v2/engine/src/boehm_gc/doc/README.MacOSX b/v2/engine/boehm_gc/doc/README.MacOSX similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.MacOSX rename to v2/engine/boehm_gc/doc/README.MacOSX diff --git a/v2/engine/src/boehm_gc/doc/README.OS2 b/v2/engine/boehm_gc/doc/README.OS2 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.OS2 rename to v2/engine/boehm_gc/doc/README.OS2 diff --git a/v2/engine/src/boehm_gc/doc/README.amiga b/v2/engine/boehm_gc/doc/README.amiga similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.amiga rename to v2/engine/boehm_gc/doc/README.amiga diff --git a/v2/engine/src/boehm_gc/doc/README.arm.cross b/v2/engine/boehm_gc/doc/README.arm.cross similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.arm.cross rename to v2/engine/boehm_gc/doc/README.arm.cross diff --git a/v2/engine/src/boehm_gc/doc/README.autoconf b/v2/engine/boehm_gc/doc/README.autoconf similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.autoconf rename to v2/engine/boehm_gc/doc/README.autoconf diff --git a/v2/engine/src/boehm_gc/doc/README.changes b/v2/engine/boehm_gc/doc/README.changes similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.changes rename to v2/engine/boehm_gc/doc/README.changes diff --git a/v2/engine/src/boehm_gc/doc/README.contributors b/v2/engine/boehm_gc/doc/README.contributors similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.contributors rename to v2/engine/boehm_gc/doc/README.contributors diff --git a/v2/engine/src/boehm_gc/doc/README.cords b/v2/engine/boehm_gc/doc/README.cords similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.cords rename to v2/engine/boehm_gc/doc/README.cords diff --git a/v2/engine/src/boehm_gc/doc/README.darwin b/v2/engine/boehm_gc/doc/README.darwin similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.darwin rename to v2/engine/boehm_gc/doc/README.darwin diff --git a/v2/engine/src/boehm_gc/doc/README.dj b/v2/engine/boehm_gc/doc/README.dj similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.dj rename to v2/engine/boehm_gc/doc/README.dj diff --git a/v2/engine/src/boehm_gc/doc/README.environment b/v2/engine/boehm_gc/doc/README.environment similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.environment rename to v2/engine/boehm_gc/doc/README.environment diff --git a/v2/engine/src/boehm_gc/doc/README.ews4800 b/v2/engine/boehm_gc/doc/README.ews4800 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.ews4800 rename to v2/engine/boehm_gc/doc/README.ews4800 diff --git a/v2/engine/src/boehm_gc/doc/README.hp b/v2/engine/boehm_gc/doc/README.hp similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.hp rename to v2/engine/boehm_gc/doc/README.hp diff --git a/v2/engine/src/boehm_gc/doc/README.linux b/v2/engine/boehm_gc/doc/README.linux similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.linux rename to v2/engine/boehm_gc/doc/README.linux diff --git a/v2/engine/src/boehm_gc/doc/README.macros b/v2/engine/boehm_gc/doc/README.macros similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.macros rename to v2/engine/boehm_gc/doc/README.macros diff --git a/v2/engine/src/boehm_gc/doc/README.rs6000 b/v2/engine/boehm_gc/doc/README.rs6000 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.rs6000 rename to v2/engine/boehm_gc/doc/README.rs6000 diff --git a/v2/engine/src/boehm_gc/doc/README.sgi b/v2/engine/boehm_gc/doc/README.sgi similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.sgi rename to v2/engine/boehm_gc/doc/README.sgi diff --git a/v2/engine/src/boehm_gc/doc/README.solaris2 b/v2/engine/boehm_gc/doc/README.solaris2 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.solaris2 rename to v2/engine/boehm_gc/doc/README.solaris2 diff --git a/v2/engine/src/boehm_gc/doc/README.uts b/v2/engine/boehm_gc/doc/README.uts similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.uts rename to v2/engine/boehm_gc/doc/README.uts diff --git a/v2/engine/src/boehm_gc/doc/README.win32 b/v2/engine/boehm_gc/doc/README.win32 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.win32 rename to v2/engine/boehm_gc/doc/README.win32 diff --git a/v2/engine/src/boehm_gc/doc/README.win64 b/v2/engine/boehm_gc/doc/README.win64 similarity index 100% rename from v2/engine/src/boehm_gc/doc/README.win64 rename to v2/engine/boehm_gc/doc/README.win64 diff --git a/v2/engine/src/boehm_gc/doc/barrett_diagram b/v2/engine/boehm_gc/doc/barrett_diagram similarity index 100% rename from v2/engine/src/boehm_gc/doc/barrett_diagram rename to v2/engine/boehm_gc/doc/barrett_diagram diff --git a/v2/engine/src/boehm_gc/doc/debugging.html b/v2/engine/boehm_gc/doc/debugging.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/debugging.html rename to v2/engine/boehm_gc/doc/debugging.html diff --git a/v2/engine/src/boehm_gc/doc/doc.am b/v2/engine/boehm_gc/doc/doc.am similarity index 100% rename from v2/engine/src/boehm_gc/doc/doc.am rename to v2/engine/boehm_gc/doc/doc.am diff --git a/v2/engine/src/boehm_gc/doc/gc.man b/v2/engine/boehm_gc/doc/gc.man similarity index 100% rename from v2/engine/src/boehm_gc/doc/gc.man rename to v2/engine/boehm_gc/doc/gc.man diff --git a/v2/engine/src/boehm_gc/doc/gcdescr.html b/v2/engine/boehm_gc/doc/gcdescr.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/gcdescr.html rename to v2/engine/boehm_gc/doc/gcdescr.html diff --git a/v2/engine/src/boehm_gc/doc/gcinterface.html b/v2/engine/boehm_gc/doc/gcinterface.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/gcinterface.html rename to v2/engine/boehm_gc/doc/gcinterface.html diff --git a/v2/engine/src/boehm_gc/doc/leak.html b/v2/engine/boehm_gc/doc/leak.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/leak.html rename to v2/engine/boehm_gc/doc/leak.html diff --git a/v2/engine/src/boehm_gc/doc/overview.html b/v2/engine/boehm_gc/doc/overview.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/overview.html rename to v2/engine/boehm_gc/doc/overview.html diff --git a/v2/engine/src/boehm_gc/doc/porting.html b/v2/engine/boehm_gc/doc/porting.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/porting.html rename to v2/engine/boehm_gc/doc/porting.html diff --git a/v2/engine/src/boehm_gc/doc/scale.html b/v2/engine/boehm_gc/doc/scale.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/scale.html rename to v2/engine/boehm_gc/doc/scale.html diff --git a/v2/engine/src/boehm_gc/doc/simple_example.html b/v2/engine/boehm_gc/doc/simple_example.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/simple_example.html rename to v2/engine/boehm_gc/doc/simple_example.html diff --git a/v2/engine/src/boehm_gc/doc/tree.html b/v2/engine/boehm_gc/doc/tree.html similarity index 100% rename from v2/engine/src/boehm_gc/doc/tree.html rename to v2/engine/boehm_gc/doc/tree.html diff --git a/v2/engine/src/boehm_gc/dyn_load.c b/v2/engine/boehm_gc/dyn_load.c similarity index 100% rename from v2/engine/src/boehm_gc/dyn_load.c rename to v2/engine/boehm_gc/dyn_load.c diff --git a/v2/engine/src/boehm_gc/finalize.c b/v2/engine/boehm_gc/finalize.c similarity index 100% rename from v2/engine/src/boehm_gc/finalize.c rename to v2/engine/boehm_gc/finalize.c diff --git a/v2/engine/src/boehm_gc/gc.mak b/v2/engine/boehm_gc/gc.mak similarity index 100% rename from v2/engine/src/boehm_gc/gc.mak rename to v2/engine/boehm_gc/gc.mak diff --git a/v2/engine/src/boehm_gc/gc_cpp.cc b/v2/engine/boehm_gc/gc_cpp.cc similarity index 100% rename from v2/engine/src/boehm_gc/gc_cpp.cc rename to v2/engine/boehm_gc/gc_cpp.cc diff --git a/v2/engine/src/boehm_gc/gc_cpp.cpp b/v2/engine/boehm_gc/gc_cpp.cpp similarity index 100% rename from v2/engine/src/boehm_gc/gc_cpp.cpp rename to v2/engine/boehm_gc/gc_cpp.cpp diff --git a/v2/engine/src/boehm_gc/gc_dlopen.c b/v2/engine/boehm_gc/gc_dlopen.c similarity index 100% rename from v2/engine/src/boehm_gc/gc_dlopen.c rename to v2/engine/boehm_gc/gc_dlopen.c diff --git a/v2/engine/src/boehm_gc/gcj_mlc.c b/v2/engine/boehm_gc/gcj_mlc.c similarity index 100% rename from v2/engine/src/boehm_gc/gcj_mlc.c rename to v2/engine/boehm_gc/gcj_mlc.c diff --git a/v2/engine/src/boehm_gc/gcname.c b/v2/engine/boehm_gc/gcname.c similarity index 100% rename from v2/engine/src/boehm_gc/gcname.c rename to v2/engine/boehm_gc/gcname.c diff --git a/v2/engine/src/boehm_gc/headers.c b/v2/engine/boehm_gc/headers.c similarity index 100% rename from v2/engine/src/boehm_gc/headers.c rename to v2/engine/boehm_gc/headers.c diff --git a/v2/engine/src/boehm_gc/hpux_test_and_clear.s b/v2/engine/boehm_gc/hpux_test_and_clear.s similarity index 100% rename from v2/engine/src/boehm_gc/hpux_test_and_clear.s rename to v2/engine/boehm_gc/hpux_test_and_clear.s diff --git a/v2/engine/src/boehm_gc/ia64_save_regs_in_stack.s b/v2/engine/boehm_gc/ia64_save_regs_in_stack.s similarity index 100% rename from v2/engine/src/boehm_gc/ia64_save_regs_in_stack.s rename to v2/engine/boehm_gc/ia64_save_regs_in_stack.s diff --git a/v2/engine/src/boehm_gc/if_mach.c b/v2/engine/boehm_gc/if_mach.c similarity index 100% rename from v2/engine/src/boehm_gc/if_mach.c rename to v2/engine/boehm_gc/if_mach.c diff --git a/v2/engine/src/boehm_gc/if_not_there.c b/v2/engine/boehm_gc/if_not_there.c similarity index 100% rename from v2/engine/src/boehm_gc/if_not_there.c rename to v2/engine/boehm_gc/if_not_there.c diff --git a/v2/engine/src/boehm_gc/include/cord.h b/v2/engine/boehm_gc/include/cord.h similarity index 100% rename from v2/engine/src/boehm_gc/include/cord.h rename to v2/engine/boehm_gc/include/cord.h diff --git a/v2/engine/src/boehm_gc/include/ec.h b/v2/engine/boehm_gc/include/ec.h similarity index 100% rename from v2/engine/src/boehm_gc/include/ec.h rename to v2/engine/boehm_gc/include/ec.h diff --git a/v2/engine/src/boehm_gc/include/gc.h b/v2/engine/boehm_gc/include/gc.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc.h rename to v2/engine/boehm_gc/include/gc.h diff --git a/v2/engine/src/boehm_gc/include/gc_allocator.h b/v2/engine/boehm_gc/include/gc_allocator.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_allocator.h rename to v2/engine/boehm_gc/include/gc_allocator.h diff --git a/v2/engine/src/boehm_gc/include/gc_amiga_redirects.h b/v2/engine/boehm_gc/include/gc_amiga_redirects.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_amiga_redirects.h rename to v2/engine/boehm_gc/include/gc_amiga_redirects.h diff --git a/v2/engine/src/boehm_gc/include/gc_backptr.h b/v2/engine/boehm_gc/include/gc_backptr.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_backptr.h rename to v2/engine/boehm_gc/include/gc_backptr.h diff --git a/v2/engine/src/boehm_gc/include/gc_config_macros.h b/v2/engine/boehm_gc/include/gc_config_macros.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_config_macros.h rename to v2/engine/boehm_gc/include/gc_config_macros.h diff --git a/v2/engine/src/boehm_gc/include/gc_cpp.h b/v2/engine/boehm_gc/include/gc_cpp.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_cpp.h rename to v2/engine/boehm_gc/include/gc_cpp.h diff --git a/v2/engine/src/boehm_gc/include/gc_gcj.h b/v2/engine/boehm_gc/include/gc_gcj.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_gcj.h rename to v2/engine/boehm_gc/include/gc_gcj.h diff --git a/v2/engine/src/boehm_gc/include/gc_inline.h b/v2/engine/boehm_gc/include/gc_inline.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_inline.h rename to v2/engine/boehm_gc/include/gc_inline.h diff --git a/v2/engine/src/boehm_gc/include/gc_mark.h b/v2/engine/boehm_gc/include/gc_mark.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_mark.h rename to v2/engine/boehm_gc/include/gc_mark.h diff --git a/v2/engine/src/boehm_gc/include/gc_pthread_redirects.h b/v2/engine/boehm_gc/include/gc_pthread_redirects.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_pthread_redirects.h rename to v2/engine/boehm_gc/include/gc_pthread_redirects.h diff --git a/v2/engine/src/boehm_gc/include/gc_tiny_fl.h b/v2/engine/boehm_gc/include/gc_tiny_fl.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_tiny_fl.h rename to v2/engine/boehm_gc/include/gc_tiny_fl.h diff --git a/v2/engine/src/boehm_gc/include/gc_typed.h b/v2/engine/boehm_gc/include/gc_typed.h similarity index 100% rename from v2/engine/src/boehm_gc/include/gc_typed.h rename to v2/engine/boehm_gc/include/gc_typed.h diff --git a/v2/engine/src/boehm_gc/include/include.am b/v2/engine/boehm_gc/include/include.am similarity index 100% rename from v2/engine/src/boehm_gc/include/include.am rename to v2/engine/boehm_gc/include/include.am diff --git a/v2/engine/src/boehm_gc/include/javaxfc.h b/v2/engine/boehm_gc/include/javaxfc.h similarity index 100% rename from v2/engine/src/boehm_gc/include/javaxfc.h rename to v2/engine/boehm_gc/include/javaxfc.h diff --git a/v2/engine/src/boehm_gc/include/leak_detector.h b/v2/engine/boehm_gc/include/leak_detector.h similarity index 100% rename from v2/engine/src/boehm_gc/include/leak_detector.h rename to v2/engine/boehm_gc/include/leak_detector.h diff --git a/v2/engine/src/boehm_gc/include/new_gc_alloc.h b/v2/engine/boehm_gc/include/new_gc_alloc.h similarity index 100% rename from v2/engine/src/boehm_gc/include/new_gc_alloc.h rename to v2/engine/boehm_gc/include/new_gc_alloc.h diff --git a/v2/engine/src/boehm_gc/include/private/cord_pos.h b/v2/engine/boehm_gc/include/private/cord_pos.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/cord_pos.h rename to v2/engine/boehm_gc/include/private/cord_pos.h diff --git a/v2/engine/src/boehm_gc/include/private/darwin_semaphore.h b/v2/engine/boehm_gc/include/private/darwin_semaphore.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/darwin_semaphore.h rename to v2/engine/boehm_gc/include/private/darwin_semaphore.h diff --git a/v2/engine/src/boehm_gc/include/private/darwin_stop_world.h b/v2/engine/boehm_gc/include/private/darwin_stop_world.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/darwin_stop_world.h rename to v2/engine/boehm_gc/include/private/darwin_stop_world.h diff --git a/v2/engine/src/boehm_gc/include/private/dbg_mlc.h b/v2/engine/boehm_gc/include/private/dbg_mlc.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/dbg_mlc.h rename to v2/engine/boehm_gc/include/private/dbg_mlc.h diff --git a/v2/engine/src/boehm_gc/include/private/gc_hdrs.h b/v2/engine/boehm_gc/include/private/gc_hdrs.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/gc_hdrs.h rename to v2/engine/boehm_gc/include/private/gc_hdrs.h diff --git a/v2/engine/src/boehm_gc/include/private/gc_locks.h b/v2/engine/boehm_gc/include/private/gc_locks.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/gc_locks.h rename to v2/engine/boehm_gc/include/private/gc_locks.h diff --git a/v2/engine/src/boehm_gc/include/private/gc_pmark.h b/v2/engine/boehm_gc/include/private/gc_pmark.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/gc_pmark.h rename to v2/engine/boehm_gc/include/private/gc_pmark.h diff --git a/v2/engine/src/boehm_gc/include/private/gc_priv.h b/v2/engine/boehm_gc/include/private/gc_priv.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/gc_priv.h rename to v2/engine/boehm_gc/include/private/gc_priv.h diff --git a/v2/engine/src/boehm_gc/include/private/gcconfig.h b/v2/engine/boehm_gc/include/private/gcconfig.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/gcconfig.h rename to v2/engine/boehm_gc/include/private/gcconfig.h diff --git a/v2/engine/src/boehm_gc/include/private/msvc_dbg.h b/v2/engine/boehm_gc/include/private/msvc_dbg.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/msvc_dbg.h rename to v2/engine/boehm_gc/include/private/msvc_dbg.h diff --git a/v2/engine/src/boehm_gc/include/private/pthread_stop_world.h b/v2/engine/boehm_gc/include/private/pthread_stop_world.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/pthread_stop_world.h rename to v2/engine/boehm_gc/include/private/pthread_stop_world.h diff --git a/v2/engine/src/boehm_gc/include/private/pthread_support.h b/v2/engine/boehm_gc/include/private/pthread_support.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/pthread_support.h rename to v2/engine/boehm_gc/include/private/pthread_support.h diff --git a/v2/engine/src/boehm_gc/include/private/specific.h b/v2/engine/boehm_gc/include/private/specific.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/specific.h rename to v2/engine/boehm_gc/include/private/specific.h diff --git a/v2/engine/src/boehm_gc/include/private/thread_local_alloc.h b/v2/engine/boehm_gc/include/private/thread_local_alloc.h similarity index 100% rename from v2/engine/src/boehm_gc/include/private/thread_local_alloc.h rename to v2/engine/boehm_gc/include/private/thread_local_alloc.h diff --git a/v2/engine/src/boehm_gc/include/weakpointer.h b/v2/engine/boehm_gc/include/weakpointer.h similarity index 100% rename from v2/engine/src/boehm_gc/include/weakpointer.h rename to v2/engine/boehm_gc/include/weakpointer.h diff --git a/v2/engine/src/boehm_gc/install-sh b/v2/engine/boehm_gc/install-sh similarity index 100% rename from v2/engine/src/boehm_gc/install-sh rename to v2/engine/boehm_gc/install-sh diff --git a/v2/engine/src/boehm_gc/libtool.m4 b/v2/engine/boehm_gc/libtool.m4 similarity index 100% rename from v2/engine/src/boehm_gc/libtool.m4 rename to v2/engine/boehm_gc/libtool.m4 diff --git a/v2/engine/src/boehm_gc/ltmain.sh b/v2/engine/boehm_gc/ltmain.sh similarity index 100% rename from v2/engine/src/boehm_gc/ltmain.sh rename to v2/engine/boehm_gc/ltmain.sh diff --git a/v2/engine/src/boehm_gc/mach_dep.c b/v2/engine/boehm_gc/mach_dep.c similarity index 100% rename from v2/engine/src/boehm_gc/mach_dep.c rename to v2/engine/boehm_gc/mach_dep.c diff --git a/v2/engine/src/boehm_gc/malloc.c b/v2/engine/boehm_gc/malloc.c similarity index 100% rename from v2/engine/src/boehm_gc/malloc.c rename to v2/engine/boehm_gc/malloc.c diff --git a/v2/engine/src/boehm_gc/mallocx.c b/v2/engine/boehm_gc/mallocx.c similarity index 100% rename from v2/engine/src/boehm_gc/mallocx.c rename to v2/engine/boehm_gc/mallocx.c diff --git a/v2/engine/src/boehm_gc/mark.c b/v2/engine/boehm_gc/mark.c similarity index 100% rename from v2/engine/src/boehm_gc/mark.c rename to v2/engine/boehm_gc/mark.c diff --git a/v2/engine/src/boehm_gc/mark_rts.c b/v2/engine/boehm_gc/mark_rts.c similarity index 100% rename from v2/engine/src/boehm_gc/mark_rts.c rename to v2/engine/boehm_gc/mark_rts.c diff --git a/v2/engine/src/boehm_gc/mips_sgi_mach_dep.s b/v2/engine/boehm_gc/mips_sgi_mach_dep.s similarity index 100% rename from v2/engine/src/boehm_gc/mips_sgi_mach_dep.s rename to v2/engine/boehm_gc/mips_sgi_mach_dep.s diff --git a/v2/engine/src/boehm_gc/mips_ultrix_mach_dep.s b/v2/engine/boehm_gc/mips_ultrix_mach_dep.s similarity index 100% rename from v2/engine/src/boehm_gc/mips_ultrix_mach_dep.s rename to v2/engine/boehm_gc/mips_ultrix_mach_dep.s diff --git a/v2/engine/src/boehm_gc/misc.c b/v2/engine/boehm_gc/misc.c similarity index 100% rename from v2/engine/src/boehm_gc/misc.c rename to v2/engine/boehm_gc/misc.c diff --git a/v2/engine/src/boehm_gc/missing b/v2/engine/boehm_gc/missing similarity index 100% rename from v2/engine/src/boehm_gc/missing rename to v2/engine/boehm_gc/missing diff --git a/v2/engine/src/boehm_gc/mkinstalldirs b/v2/engine/boehm_gc/mkinstalldirs similarity index 100% rename from v2/engine/src/boehm_gc/mkinstalldirs rename to v2/engine/boehm_gc/mkinstalldirs diff --git a/v2/engine/src/boehm_gc/msvc_dbg.c b/v2/engine/boehm_gc/msvc_dbg.c similarity index 100% rename from v2/engine/src/boehm_gc/msvc_dbg.c rename to v2/engine/boehm_gc/msvc_dbg.c diff --git a/v2/engine/src/boehm_gc/new_hblk.c b/v2/engine/boehm_gc/new_hblk.c similarity index 100% rename from v2/engine/src/boehm_gc/new_hblk.c rename to v2/engine/boehm_gc/new_hblk.c diff --git a/v2/engine/src/boehm_gc/obj_map.c b/v2/engine/boehm_gc/obj_map.c similarity index 100% rename from v2/engine/src/boehm_gc/obj_map.c rename to v2/engine/boehm_gc/obj_map.c diff --git a/v2/engine/src/boehm_gc/os_dep.c b/v2/engine/boehm_gc/os_dep.c similarity index 100% rename from v2/engine/src/boehm_gc/os_dep.c rename to v2/engine/boehm_gc/os_dep.c diff --git a/v2/engine/src/boehm_gc/pcr_interface.c b/v2/engine/boehm_gc/pcr_interface.c similarity index 100% rename from v2/engine/src/boehm_gc/pcr_interface.c rename to v2/engine/boehm_gc/pcr_interface.c diff --git a/v2/engine/src/boehm_gc/pthread_stop_world.c b/v2/engine/boehm_gc/pthread_stop_world.c similarity index 100% rename from v2/engine/src/boehm_gc/pthread_stop_world.c rename to v2/engine/boehm_gc/pthread_stop_world.c diff --git a/v2/engine/src/boehm_gc/pthread_support.c b/v2/engine/boehm_gc/pthread_support.c similarity index 100% rename from v2/engine/src/boehm_gc/pthread_support.c rename to v2/engine/boehm_gc/pthread_support.c diff --git a/v2/engine/src/boehm_gc/ptr_chck.c b/v2/engine/boehm_gc/ptr_chck.c similarity index 100% rename from v2/engine/src/boehm_gc/ptr_chck.c rename to v2/engine/boehm_gc/ptr_chck.c diff --git a/v2/engine/src/boehm_gc/real_malloc.c b/v2/engine/boehm_gc/real_malloc.c similarity index 100% rename from v2/engine/src/boehm_gc/real_malloc.c rename to v2/engine/boehm_gc/real_malloc.c diff --git a/v2/engine/src/boehm_gc/reclaim.c b/v2/engine/boehm_gc/reclaim.c similarity index 100% rename from v2/engine/src/boehm_gc/reclaim.c rename to v2/engine/boehm_gc/reclaim.c diff --git a/v2/engine/src/boehm_gc/rs6000_mach_dep.s b/v2/engine/boehm_gc/rs6000_mach_dep.s similarity index 100% rename from v2/engine/src/boehm_gc/rs6000_mach_dep.s rename to v2/engine/boehm_gc/rs6000_mach_dep.s diff --git a/v2/engine/src/boehm_gc/setjmp_t.c b/v2/engine/boehm_gc/setjmp_t.c similarity index 100% rename from v2/engine/src/boehm_gc/setjmp_t.c rename to v2/engine/boehm_gc/setjmp_t.c diff --git a/v2/engine/src/boehm_gc/sparc_mach_dep.S b/v2/engine/boehm_gc/sparc_mach_dep.S similarity index 100% rename from v2/engine/src/boehm_gc/sparc_mach_dep.S rename to v2/engine/boehm_gc/sparc_mach_dep.S diff --git a/v2/engine/src/boehm_gc/sparc_netbsd_mach_dep.s b/v2/engine/boehm_gc/sparc_netbsd_mach_dep.s similarity index 100% rename from v2/engine/src/boehm_gc/sparc_netbsd_mach_dep.s rename to v2/engine/boehm_gc/sparc_netbsd_mach_dep.s diff --git a/v2/engine/src/boehm_gc/sparc_sunos4_mach_dep.s b/v2/engine/boehm_gc/sparc_sunos4_mach_dep.s similarity index 100% rename from v2/engine/src/boehm_gc/sparc_sunos4_mach_dep.s rename to v2/engine/boehm_gc/sparc_sunos4_mach_dep.s diff --git a/v2/engine/src/boehm_gc/specific.c b/v2/engine/boehm_gc/specific.c similarity index 100% rename from v2/engine/src/boehm_gc/specific.c rename to v2/engine/boehm_gc/specific.c diff --git a/v2/engine/src/boehm_gc/stubborn.c b/v2/engine/boehm_gc/stubborn.c similarity index 100% rename from v2/engine/src/boehm_gc/stubborn.c rename to v2/engine/boehm_gc/stubborn.c diff --git a/v2/engine/src/boehm_gc/tests/leak_test.c b/v2/engine/boehm_gc/tests/leak_test.c similarity index 100% rename from v2/engine/src/boehm_gc/tests/leak_test.c rename to v2/engine/boehm_gc/tests/leak_test.c diff --git a/v2/engine/src/boehm_gc/tests/middle.c b/v2/engine/boehm_gc/tests/middle.c similarity index 100% rename from v2/engine/src/boehm_gc/tests/middle.c rename to v2/engine/boehm_gc/tests/middle.c diff --git a/v2/engine/src/boehm_gc/tests/test.c b/v2/engine/boehm_gc/tests/test.c similarity index 100% rename from v2/engine/src/boehm_gc/tests/test.c rename to v2/engine/boehm_gc/tests/test.c diff --git a/v2/engine/src/boehm_gc/tests/test_cpp.cc b/v2/engine/boehm_gc/tests/test_cpp.cc similarity index 100% rename from v2/engine/src/boehm_gc/tests/test_cpp.cc rename to v2/engine/boehm_gc/tests/test_cpp.cc diff --git a/v2/engine/src/boehm_gc/tests/tests.am b/v2/engine/boehm_gc/tests/tests.am similarity index 100% rename from v2/engine/src/boehm_gc/tests/tests.am rename to v2/engine/boehm_gc/tests/tests.am diff --git a/v2/engine/src/boehm_gc/tests/thread_leak_test.c b/v2/engine/boehm_gc/tests/thread_leak_test.c similarity index 100% rename from v2/engine/src/boehm_gc/tests/thread_leak_test.c rename to v2/engine/boehm_gc/tests/thread_leak_test.c diff --git a/v2/engine/src/boehm_gc/thread_local_alloc.c b/v2/engine/boehm_gc/thread_local_alloc.c similarity index 100% rename from v2/engine/src/boehm_gc/thread_local_alloc.c rename to v2/engine/boehm_gc/thread_local_alloc.c diff --git a/v2/engine/src/boehm_gc/threadlibs.c b/v2/engine/boehm_gc/threadlibs.c similarity index 100% rename from v2/engine/src/boehm_gc/threadlibs.c rename to v2/engine/boehm_gc/threadlibs.c diff --git a/v2/engine/src/boehm_gc/typd_mlc.c b/v2/engine/boehm_gc/typd_mlc.c similarity index 100% rename from v2/engine/src/boehm_gc/typd_mlc.c rename to v2/engine/boehm_gc/typd_mlc.c diff --git a/v2/engine/src/boehm_gc/version.h b/v2/engine/boehm_gc/version.h similarity index 100% rename from v2/engine/src/boehm_gc/version.h rename to v2/engine/boehm_gc/version.h diff --git a/v2/engine/src/boehm_gc/win32_threads.c b/v2/engine/boehm_gc/win32_threads.c similarity index 100% rename from v2/engine/src/boehm_gc/win32_threads.c rename to v2/engine/boehm_gc/win32_threads.c diff --git a/v2/engine/src/boost-jam.spec b/v2/engine/boost-jam.spec similarity index 100% rename from v2/engine/src/boost-jam.spec rename to v2/engine/boost-jam.spec diff --git a/v2/engine/src/build.bat b/v2/engine/build.bat similarity index 100% rename from v2/engine/src/build.bat rename to v2/engine/build.bat diff --git a/v2/engine/src/build.jam b/v2/engine/build.jam similarity index 100% rename from v2/engine/src/build.jam rename to v2/engine/build.jam diff --git a/v2/engine/src/build.sh b/v2/engine/build.sh similarity index 100% rename from v2/engine/src/build.sh rename to v2/engine/build.sh diff --git a/v2/engine/src/build_vms.com b/v2/engine/build_vms.com similarity index 100% rename from v2/engine/src/build_vms.com rename to v2/engine/build_vms.com diff --git a/v2/engine/src/builtins.c b/v2/engine/builtins.c similarity index 100% rename from v2/engine/src/builtins.c rename to v2/engine/builtins.c diff --git a/v2/engine/src/builtins.h b/v2/engine/builtins.h similarity index 100% rename from v2/engine/src/builtins.h rename to v2/engine/builtins.h diff --git a/v2/engine/src/bump_version.py b/v2/engine/bump_version.py similarity index 100% rename from v2/engine/src/bump_version.py rename to v2/engine/bump_version.py diff --git a/v2/engine/src/class.c b/v2/engine/class.c similarity index 100% rename from v2/engine/src/class.c rename to v2/engine/class.c diff --git a/v2/engine/src/class.h b/v2/engine/class.h similarity index 100% rename from v2/engine/src/class.h rename to v2/engine/class.h diff --git a/v2/engine/src/command.c b/v2/engine/command.c similarity index 100% rename from v2/engine/src/command.c rename to v2/engine/command.c diff --git a/v2/engine/src/command.h b/v2/engine/command.h similarity index 100% rename from v2/engine/src/command.h rename to v2/engine/command.h diff --git a/v2/engine/src/compile.c b/v2/engine/compile.c similarity index 100% rename from v2/engine/src/compile.c rename to v2/engine/compile.c diff --git a/v2/engine/src/compile.h b/v2/engine/compile.h similarity index 100% rename from v2/engine/src/compile.h rename to v2/engine/compile.h diff --git a/v2/engine/src/debian/changelog b/v2/engine/debian/changelog similarity index 100% rename from v2/engine/src/debian/changelog rename to v2/engine/debian/changelog diff --git a/v2/engine/src/debian/control b/v2/engine/debian/control similarity index 100% rename from v2/engine/src/debian/control rename to v2/engine/debian/control diff --git a/v2/engine/src/debian/copyright b/v2/engine/debian/copyright similarity index 100% rename from v2/engine/src/debian/copyright rename to v2/engine/debian/copyright diff --git a/v2/engine/src/debian/jam.man.sgml b/v2/engine/debian/jam.man.sgml similarity index 100% rename from v2/engine/src/debian/jam.man.sgml rename to v2/engine/debian/jam.man.sgml diff --git a/v2/engine/src/debian/rules b/v2/engine/debian/rules similarity index 100% rename from v2/engine/src/debian/rules rename to v2/engine/debian/rules diff --git a/v2/engine/src/debug.c b/v2/engine/debug.c similarity index 100% rename from v2/engine/src/debug.c rename to v2/engine/debug.c diff --git a/v2/engine/src/debug.h b/v2/engine/debug.h similarity index 100% rename from v2/engine/src/debug.h rename to v2/engine/debug.h diff --git a/v2/engine/src/execcmd.h b/v2/engine/execcmd.h similarity index 100% rename from v2/engine/src/execcmd.h rename to v2/engine/execcmd.h diff --git a/v2/engine/src/execmac.c b/v2/engine/execmac.c similarity index 100% rename from v2/engine/src/execmac.c rename to v2/engine/execmac.c diff --git a/v2/engine/src/execnt.c b/v2/engine/execnt.c similarity index 100% rename from v2/engine/src/execnt.c rename to v2/engine/execnt.c diff --git a/v2/engine/src/execunix.c b/v2/engine/execunix.c similarity index 100% rename from v2/engine/src/execunix.c rename to v2/engine/execunix.c diff --git a/v2/engine/src/execvms.c b/v2/engine/execvms.c similarity index 100% rename from v2/engine/src/execvms.c rename to v2/engine/execvms.c diff --git a/v2/engine/src/expand.c b/v2/engine/expand.c similarity index 100% rename from v2/engine/src/expand.c rename to v2/engine/expand.c diff --git a/v2/engine/src/expand.h b/v2/engine/expand.h similarity index 100% rename from v2/engine/src/expand.h rename to v2/engine/expand.h diff --git a/v2/engine/src/filemac.c b/v2/engine/filemac.c similarity index 100% rename from v2/engine/src/filemac.c rename to v2/engine/filemac.c diff --git a/v2/engine/src/filent.c b/v2/engine/filent.c similarity index 100% rename from v2/engine/src/filent.c rename to v2/engine/filent.c diff --git a/v2/engine/src/fileos2.c b/v2/engine/fileos2.c similarity index 100% rename from v2/engine/src/fileos2.c rename to v2/engine/fileos2.c diff --git a/v2/engine/src/filesys.c b/v2/engine/filesys.c similarity index 100% rename from v2/engine/src/filesys.c rename to v2/engine/filesys.c diff --git a/v2/engine/src/filesys.h b/v2/engine/filesys.h similarity index 100% rename from v2/engine/src/filesys.h rename to v2/engine/filesys.h diff --git a/v2/engine/src/fileunix.c b/v2/engine/fileunix.c similarity index 100% rename from v2/engine/src/fileunix.c rename to v2/engine/fileunix.c diff --git a/v2/engine/src/filevms.c b/v2/engine/filevms.c similarity index 100% rename from v2/engine/src/filevms.c rename to v2/engine/filevms.c diff --git a/v2/engine/src/frames.c b/v2/engine/frames.c similarity index 100% rename from v2/engine/src/frames.c rename to v2/engine/frames.c diff --git a/v2/engine/src/frames.h b/v2/engine/frames.h similarity index 100% rename from v2/engine/src/frames.h rename to v2/engine/frames.h diff --git a/v2/engine/src/glob.c b/v2/engine/glob.c similarity index 100% rename from v2/engine/src/glob.c rename to v2/engine/glob.c diff --git a/v2/engine/src/hash.c b/v2/engine/hash.c similarity index 100% rename from v2/engine/src/hash.c rename to v2/engine/hash.c diff --git a/v2/engine/src/hash.h b/v2/engine/hash.h similarity index 100% rename from v2/engine/src/hash.h rename to v2/engine/hash.h diff --git a/v2/engine/src/hcache.c b/v2/engine/hcache.c similarity index 100% rename from v2/engine/src/hcache.c rename to v2/engine/hcache.c diff --git a/v2/engine/src/hcache.h b/v2/engine/hcache.h similarity index 100% rename from v2/engine/src/hcache.h rename to v2/engine/hcache.h diff --git a/v2/engine/src/hdrmacro.c b/v2/engine/hdrmacro.c similarity index 100% rename from v2/engine/src/hdrmacro.c rename to v2/engine/hdrmacro.c diff --git a/v2/engine/src/hdrmacro.h b/v2/engine/hdrmacro.h similarity index 100% rename from v2/engine/src/hdrmacro.h rename to v2/engine/hdrmacro.h diff --git a/v2/engine/src/headers.c b/v2/engine/headers.c similarity index 100% rename from v2/engine/src/headers.c rename to v2/engine/headers.c diff --git a/v2/engine/src/headers.h b/v2/engine/headers.h similarity index 100% rename from v2/engine/src/headers.h rename to v2/engine/headers.h diff --git a/v2/engine/src/jam.c b/v2/engine/jam.c similarity index 100% rename from v2/engine/src/jam.c rename to v2/engine/jam.c diff --git a/v2/engine/src/jam.h b/v2/engine/jam.h similarity index 100% rename from v2/engine/src/jam.h rename to v2/engine/jam.h diff --git a/v2/engine/src/jambase.c b/v2/engine/jambase.c similarity index 100% rename from v2/engine/src/jambase.c rename to v2/engine/jambase.c diff --git a/v2/engine/src/jambase.h b/v2/engine/jambase.h similarity index 100% rename from v2/engine/src/jambase.h rename to v2/engine/jambase.h diff --git a/v2/engine/src/jamgram.c b/v2/engine/jamgram.c similarity index 100% rename from v2/engine/src/jamgram.c rename to v2/engine/jamgram.c diff --git a/v2/engine/src/jamgram.h b/v2/engine/jamgram.h similarity index 100% rename from v2/engine/src/jamgram.h rename to v2/engine/jamgram.h diff --git a/v2/engine/src/jamgram.y b/v2/engine/jamgram.y similarity index 100% rename from v2/engine/src/jamgram.y rename to v2/engine/jamgram.y diff --git a/v2/engine/src/jamgram.yy b/v2/engine/jamgram.yy similarity index 100% rename from v2/engine/src/jamgram.yy rename to v2/engine/jamgram.yy diff --git a/v2/engine/src/jamgramtab.h b/v2/engine/jamgramtab.h similarity index 100% rename from v2/engine/src/jamgramtab.h rename to v2/engine/jamgramtab.h diff --git a/v2/engine/src/lists.c b/v2/engine/lists.c similarity index 100% rename from v2/engine/src/lists.c rename to v2/engine/lists.c diff --git a/v2/engine/src/lists.h b/v2/engine/lists.h similarity index 100% rename from v2/engine/src/lists.h rename to v2/engine/lists.h diff --git a/v2/engine/src/make.c b/v2/engine/make.c similarity index 100% rename from v2/engine/src/make.c rename to v2/engine/make.c diff --git a/v2/engine/src/make.h b/v2/engine/make.h similarity index 100% rename from v2/engine/src/make.h rename to v2/engine/make.h diff --git a/v2/engine/src/make1.c b/v2/engine/make1.c similarity index 100% rename from v2/engine/src/make1.c rename to v2/engine/make1.c diff --git a/v2/engine/src/md5.c b/v2/engine/md5.c similarity index 100% rename from v2/engine/src/md5.c rename to v2/engine/md5.c diff --git a/v2/engine/src/md5.h b/v2/engine/md5.h similarity index 100% rename from v2/engine/src/md5.h rename to v2/engine/md5.h diff --git a/v2/engine/src/mem.c b/v2/engine/mem.c similarity index 100% rename from v2/engine/src/mem.c rename to v2/engine/mem.c diff --git a/v2/engine/src/mem.h b/v2/engine/mem.h similarity index 100% rename from v2/engine/src/mem.h rename to v2/engine/mem.h diff --git a/v2/engine/src/mkjambase.c b/v2/engine/mkjambase.c similarity index 100% rename from v2/engine/src/mkjambase.c rename to v2/engine/mkjambase.c diff --git a/v2/engine/src/modules.c b/v2/engine/modules.c similarity index 100% rename from v2/engine/src/modules.c rename to v2/engine/modules.c diff --git a/v2/engine/src/modules.h b/v2/engine/modules.h similarity index 100% rename from v2/engine/src/modules.h rename to v2/engine/modules.h diff --git a/v2/engine/src/modules/order.c b/v2/engine/modules/order.c similarity index 100% rename from v2/engine/src/modules/order.c rename to v2/engine/modules/order.c diff --git a/v2/engine/src/modules/path.c b/v2/engine/modules/path.c similarity index 100% rename from v2/engine/src/modules/path.c rename to v2/engine/modules/path.c diff --git a/v2/engine/src/modules/property-set.c b/v2/engine/modules/property-set.c similarity index 100% rename from v2/engine/src/modules/property-set.c rename to v2/engine/modules/property-set.c diff --git a/v2/engine/src/modules/readme.txt b/v2/engine/modules/readme.txt similarity index 100% rename from v2/engine/src/modules/readme.txt rename to v2/engine/modules/readme.txt diff --git a/v2/engine/src/modules/regex.c b/v2/engine/modules/regex.c similarity index 100% rename from v2/engine/src/modules/regex.c rename to v2/engine/modules/regex.c diff --git a/v2/engine/src/modules/sequence.c b/v2/engine/modules/sequence.c similarity index 100% rename from v2/engine/src/modules/sequence.c rename to v2/engine/modules/sequence.c diff --git a/v2/engine/src/modules/set.c b/v2/engine/modules/set.c similarity index 100% rename from v2/engine/src/modules/set.c rename to v2/engine/modules/set.c diff --git a/v2/engine/src/native.c b/v2/engine/native.c similarity index 100% rename from v2/engine/src/native.c rename to v2/engine/native.c diff --git a/v2/engine/src/native.h b/v2/engine/native.h similarity index 100% rename from v2/engine/src/native.h rename to v2/engine/native.h diff --git a/v2/engine/src/newstr.c b/v2/engine/newstr.c similarity index 100% rename from v2/engine/src/newstr.c rename to v2/engine/newstr.c diff --git a/v2/engine/src/newstr.h b/v2/engine/newstr.h similarity index 100% rename from v2/engine/src/newstr.h rename to v2/engine/newstr.h diff --git a/v2/engine/src/option.c b/v2/engine/option.c similarity index 100% rename from v2/engine/src/option.c rename to v2/engine/option.c diff --git a/v2/engine/src/option.h b/v2/engine/option.h similarity index 100% rename from v2/engine/src/option.h rename to v2/engine/option.h diff --git a/v2/engine/src/output.c b/v2/engine/output.c similarity index 100% rename from v2/engine/src/output.c rename to v2/engine/output.c diff --git a/v2/engine/src/output.h b/v2/engine/output.h similarity index 100% rename from v2/engine/src/output.h rename to v2/engine/output.h diff --git a/v2/engine/src/parse.c b/v2/engine/parse.c similarity index 100% rename from v2/engine/src/parse.c rename to v2/engine/parse.c diff --git a/v2/engine/src/parse.h b/v2/engine/parse.h similarity index 100% rename from v2/engine/src/parse.h rename to v2/engine/parse.h diff --git a/v2/engine/src/patchlevel.h b/v2/engine/patchlevel.h similarity index 100% rename from v2/engine/src/patchlevel.h rename to v2/engine/patchlevel.h diff --git a/v2/engine/src/pathmac.c b/v2/engine/pathmac.c similarity index 100% rename from v2/engine/src/pathmac.c rename to v2/engine/pathmac.c diff --git a/v2/engine/src/pathsys.h b/v2/engine/pathsys.h similarity index 100% rename from v2/engine/src/pathsys.h rename to v2/engine/pathsys.h diff --git a/v2/engine/src/pathunix.c b/v2/engine/pathunix.c similarity index 100% rename from v2/engine/src/pathunix.c rename to v2/engine/pathunix.c diff --git a/v2/engine/src/pathvms.c b/v2/engine/pathvms.c similarity index 100% rename from v2/engine/src/pathvms.c rename to v2/engine/pathvms.c diff --git a/v2/engine/src/pwd.c b/v2/engine/pwd.c similarity index 100% rename from v2/engine/src/pwd.c rename to v2/engine/pwd.c diff --git a/v2/engine/src/pwd.h b/v2/engine/pwd.h similarity index 100% rename from v2/engine/src/pwd.h rename to v2/engine/pwd.h diff --git a/v2/engine/src/regexp.c b/v2/engine/regexp.c similarity index 100% rename from v2/engine/src/regexp.c rename to v2/engine/regexp.c diff --git a/v2/engine/src/regexp.h b/v2/engine/regexp.h similarity index 100% rename from v2/engine/src/regexp.h rename to v2/engine/regexp.h diff --git a/v2/engine/src/rules.c b/v2/engine/rules.c similarity index 100% rename from v2/engine/src/rules.c rename to v2/engine/rules.c diff --git a/v2/engine/src/rules.h b/v2/engine/rules.h similarity index 100% rename from v2/engine/src/rules.h rename to v2/engine/rules.h diff --git a/v2/engine/src/scan.c b/v2/engine/scan.c similarity index 100% rename from v2/engine/src/scan.c rename to v2/engine/scan.c diff --git a/v2/engine/src/scan.h b/v2/engine/scan.h similarity index 100% rename from v2/engine/src/scan.h rename to v2/engine/scan.h diff --git a/v2/engine/src/search.c b/v2/engine/search.c similarity index 100% rename from v2/engine/src/search.c rename to v2/engine/search.c diff --git a/v2/engine/src/search.h b/v2/engine/search.h similarity index 100% rename from v2/engine/src/search.h rename to v2/engine/search.h diff --git a/v2/engine/src/strings.c b/v2/engine/strings.c similarity index 100% rename from v2/engine/src/strings.c rename to v2/engine/strings.c diff --git a/v2/engine/src/strings.h b/v2/engine/strings.h similarity index 100% rename from v2/engine/src/strings.h rename to v2/engine/strings.h diff --git a/v2/engine/src/subst.c b/v2/engine/subst.c similarity index 100% rename from v2/engine/src/subst.c rename to v2/engine/subst.c diff --git a/v2/engine/src/timestamp.c b/v2/engine/timestamp.c similarity index 100% rename from v2/engine/src/timestamp.c rename to v2/engine/timestamp.c diff --git a/v2/engine/src/timestamp.h b/v2/engine/timestamp.h similarity index 100% rename from v2/engine/src/timestamp.h rename to v2/engine/timestamp.h diff --git a/v2/engine/src/variable.c b/v2/engine/variable.c similarity index 100% rename from v2/engine/src/variable.c rename to v2/engine/variable.c diff --git a/v2/engine/src/variable.h b/v2/engine/variable.h similarity index 100% rename from v2/engine/src/variable.h rename to v2/engine/variable.h diff --git a/v2/engine/src/w32_getreg.c b/v2/engine/w32_getreg.c similarity index 100% rename from v2/engine/src/w32_getreg.c rename to v2/engine/w32_getreg.c diff --git a/v2/engine/src/yyacc.c b/v2/engine/yyacc.c similarity index 100% rename from v2/engine/src/yyacc.c rename to v2/engine/yyacc.c From facca8c213793c4138a0ebca01fad017cb02cd88 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 3 Feb 2011 20:57:09 +0000 Subject: [PATCH 165/165] Update boostbook module documentation. [SVN r68628] --- v2/tools/boostbook.jam | 50 ++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/v2/tools/boostbook.jam b/v2/tools/boostbook.jam index 0c4c0ca68..b7f1965d9 100644 --- a/v2/tools/boostbook.jam +++ b/v2/tools/boostbook.jam @@ -7,6 +7,23 @@ # This module defines rules to handle generation of documentation # from BoostBook sources. +# +# The type of output is controlled by the feature which can +# have the following values:: +# +# * html: Generates html documention. This is the default. +# * xhtml: Generates xhtml documentation +# * htmlhelp: Generates html help output. +# * onehtml: Generates a single html page. +# * man: Generates man pages. +# * pdf: Generates pdf documentation. +# * ps: Generates postscript output. +# * docbook: Generates docbook XML. +# * fo: Generates XSL formating objects. +# * tests: Extracts test cases from the boostbook XML. +# +# format is an implicit feature, so typing pdf on the command +# line (for example) is a short-cut for format=pdf. import "class" : new ; import common ; @@ -55,20 +72,21 @@ type.register TESTS : tests ; type.register BOOSTBOOK_MAIN ; -# Initialize BoostBook support. The parameters are: -# docbook-xsl-dir: The DocBook XSL stylesheet directory. If not provided, -# we use DOCBOOK_XSL_DIR from the environment (if available) or look in -# standard locations. Otherwise, we let the XML processor load the -# stylesheets remotely. -# -# docbook-dtd-dir: The DocBook DTD directory. If not provided, we use -# DOCBOOK_DTD_DIR From the environment (if available) or look in -# standard locations. Otherwise, we let the XML processor load the -# DTD remotely. -# -# boost-book-dir: The BoostBook directory with the DTD and XSL subdirs. -# -rule init ( docbook-xsl-dir ? : docbook-dtd-dir ? : boostbook-dir ? ) +# Initialize BoostBook support. +rule init ( + docbook-xsl-dir ? # The DocBook XSL stylesheet directory. If not + # provided, we use DOCBOOK_XSL_DIR from the environment + # (if available) or look in standard locations. + # Otherwise, we let the XML processor load the + # stylesheets remotely. + + : docbook-dtd-dir ? # The DocBook DTD directory. If not provided, we use + # DOCBOOK_DTD_DIR From the environment (if available) or + # look in standard locations. Otherwise, we let the XML + # processor load the DTD remotely. + + : boostbook-dir ? # The BoostBook directory with the DTD and XSL subdirs. +) { if ! $(.initialized) @@ -527,6 +545,7 @@ class boostbook-generator : generator generators.register [ new boostbook-generator boostbook.main : : BOOSTBOOK_MAIN ] ; +# Creates a boostbook target. rule boostbook ( target-name : sources * : requirements * : default-build * ) { local project = [ project.current ] ; @@ -577,9 +596,6 @@ class xinclude-scanner : scanner scanner.register xinclude-scanner : xsl:path ; type.set-scanner XML : xinclude-scanner ; -############################################################################# -# Testsuite handling -############################################################################# rule boostbook-to-tests ( target : source : properties * ) { local boost_root = [ modules.peek : BOOST_ROOT ] ;