Index: build/project.py =================================================================== --- build/project.py (revision 64141) +++ build/project.py (working copy) @@ -978,7 +978,6 @@ "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 @@ 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: Index: build/toolset.py =================================================================== --- build/toolset.py (revision 64141) +++ build/toolset.py (working copy) @@ -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 @@ # 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. Index: build/feature.py =================================================================== --- build/feature.py (revision 64141) +++ build/feature.py (working copy) @@ -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 @@ # 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 Index: engine/src/rules.c =================================================================== --- engine/src/rules.c (revision 64141) +++ engine/src/rules.c (working copy) @@ -421,6 +421,7 @@ v->symbol = newstr( symbol ); v->value = value; v->next = head; + v->multiple = 0; head = v; } else if ( flag == VAR_APPEND ) Index: engine/src/rules.h =================================================================== --- engine/src/rules.h (revision 64141) +++ engine/src/rules.h (working copy) @@ -119,6 +119,7 @@ SETTINGS * next; char * symbol; /* symbol name for var_set() */ LIST * value; /* symbol value for var_set() */ + int multiple; }; /* TARGETS - a chain of TARGETs. */ Index: engine/src/compile.c =================================================================== --- engine/src/compile.c (revision 64151) +++ engine/src/compile.c (working copy) @@ -707,6 +707,7 @@ 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 @@ 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 @@ } } - 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 @@ 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); } - /* Steals reference to 'arg' */ - PyTuple_SetItem( arguments, i, arg ); } + else + { + arguments = PyTuple_New( frame->args->count ); + for ( i = 0; i < frame->args->count; ++i ) + { + PyObject * arg = PyList_New(0); + LIST* l = lol_get( frame->args, i); + + for ( ; l; l = l->next ) + { + PyObject * v = PyString_FromString(l->string); + PyList_Append( arg, v ); + Py_DECREF(v); + } + /* Steals reference to 'arg' */ + PyTuple_SetItem( arguments, i, arg ); + } + } frame_before_python_call = frame; - py_result = PyObject_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 ) ) Index: engine/src/builtins.c =================================================================== --- engine/src/builtins.c (revision 64141) +++ engine/src/builtins.c (working copy) @@ -1902,8 +1902,12 @@ /* - * 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 @@ 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,7 +1938,23 @@ 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; } Index: engine/src/lists.c =================================================================== --- engine/src/lists.c (revision 64141) +++ engine/src/lists.c (working copy) @@ -303,3 +303,37 @@ 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 Index: engine/src/lists.h =================================================================== --- engine/src/lists.h (revision 64141) +++ engine/src/lists.h (working copy) @@ -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 @@ 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 + Index: util/__init__.py =================================================================== --- util/__init__.py (revision 64141) +++ util/__init__.py (working copy) @@ -0,0 +1,8 @@ + +def bjam_signature(s): + + def wrap(f): + f.bjam_signature = s + return f + + return wrap