2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-17 13:42:14 +00:00

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]
This commit is contained in:
Vladimir Prus
2010-07-19 13:20:51 +00:00
parent 85352e0f67
commit 72a0c82fcd
10 changed files with 136 additions and 21 deletions

View File

@@ -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

View File

@@ -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:

View File

@@ -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.

View File

@@ -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;

View File

@@ -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 ) )

View File

@@ -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

View File

@@ -45,6 +45,10 @@
#ifndef LISTS_DWA20011022_H
# define LISTS_DWA20011022_H
#ifdef HAVE_PYTHON
#include <Python.h>
#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

View File

@@ -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 )

View File

@@ -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. */

View File

@@ -0,0 +1,8 @@
def bjam_signature(s):
def wrap(f):
f.bjam_signature = s
return f
return wrap