2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-16 01:12:13 +00:00

Initial Python integration support. Disabled by default, find and

change the setting of HAVE_PYTHON in build.jam to enable it.


[SVN r27559]
This commit is contained in:
Vladimir Prus
2005-03-05 07:59:14 +00:00
parent 5ce1b6f825
commit e98ac4ece6
16 changed files with 696 additions and 4 deletions

View File

@@ -17,6 +17,11 @@ VERSION = 3$(.)1$(.)10 ;
RELEASE = 1 ;
LICENSE = 1_0 ;
HAVE_PYTHON = 0 ;
PYTHON_INCUDES = /usr/include/python2.3 ;
PYTHON_LIB = -lpython2.3 ;
# Generate development debug binaries?
if --debug in $(ARGV)
{
@@ -326,6 +331,16 @@ if $(VMS)
}
--defs += YYSTACKSIZE=5000 ;
if $(HAVE_PYTHON) = 1
{
--defs += HAVE_PYTHON ;
--flags += -I$(PYTHON_INCUDES) ;
--flags += -Wno-long-long ;
--libs += $(PYTHON_LIB) ;
}
# The basic symbolic targets...
NOTFILE all clean dist ;
ALWAYS clean ;

View File

@@ -22,6 +22,7 @@
# include "hdrmacro.h"
# include "compile.h"
# include "native.h"
# include "variable.h"
# include <ctype.h>
/*
@@ -287,8 +288,14 @@ load_builtins()
builtin_check_if_file, 0, args );
}
#ifdef HAVE_PYTHON
{
char * args[] = { "python-module", ":", "function", ":",
"jam-module", ":", "rule-name", 0 };
bind_builtin( "PYTHON_IMPORT_RULE",
builtin_python_import_rule, 0, args );
}
#endif
# ifdef OS_NT
{
@@ -1238,6 +1245,92 @@ LIST *builtin_check_if_file( PARSE *parse, FRAME *frame )
}
#ifdef HAVE_PYTHON
LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame )
{
static int first_time = 1;
char* python_module = lol_get( frame->args, 0 )->string;
char* python_function = lol_get( frame->args, 1 )->string;
char* jam_module = lol_get( frame->args, 2 )->string;
char* jam_rule = lol_get( frame->args, 3 )->string;
PyObject *pName, *pModule, *pDict, *pFunc;
if (first_time)
{
/* At the first invocation, we add the value of the
global EXTRA_PYTHONPATH to the sys.path Python
variable.
*/
LIST* extra = 0;
module_t* outer_module = frame->module;
first_time = 0;
if ( outer_module != root_module())
{
exit_module( outer_module );
enter_module( root_module());
}
extra = var_get("EXTRA_PYTHONPATH");
if ( outer_module != root_module())
{
exit_module( root_module());
enter_module( outer_module );
}
for(; extra; extra = extra->next)
{
string buf[1];
string_new(buf);
string_append(buf, "import sys\nsys.path.append(\"");
string_append(buf, extra->string);
string_append(buf, "\")\n");
PyRun_SimpleString(buf->value);
string_free(buf);
}
}
pName = PyString_FromString(python_module);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, python_function);
if (pFunc && PyCallable_Check(pFunc)) {
module_t* m = bindmodule(jam_module);
RULE* r = bindrule( jam_rule, m );
/* Make pFunc owned */
Py_INCREF(pFunc);
r->python_function = pFunc;
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", python_function);
}
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", python_module);
}
return L0;
}
#endif
void lol_build( LOL* lol, char** elements )
{
LIST* l = L0;
@@ -1261,3 +1354,92 @@ void lol_build( LOL* lol, char** elements )
lol_add( lol, l );
}
#ifdef HAVE_PYTHON
/** Calls the bjam rule specified by name passed in 'args'.
The name is looked up in context of bjam's 'python_interface'
module. Returns the list of string retured by the rule.
*/
PyObject*
bjam_call(PyObject* self, PyObject* args)
{
FRAME inner[1];
LIST *result;
PARSE *p;
char* rulename;
/* Build up the list of arg lists */
frame_init( inner );
inner->prev = 0;
inner->prev_user = 0;
inner->module = bindmodule("python_interface");
inner->procedure = 0;
/* Extract the rule name and arguments from 'args' */
/* PyTuple_GetItem returns borrowed reference */
rulename = PyString_AsString(PyTuple_GetItem(args, 0));
{
int i = 1;
int size = PyTuple_Size(args);
for( ; i < size; ++i) {
PyObject* a = PyTuple_GetItem(args, i);
if (PyString_Check(a))
{
lol_add(inner->args,
list_new(0, newstr(PyString_AsString(a))));
}
else if (PySequence_Check(a))
{
LIST* l = 0;
int s = PySequence_Size(a);
int i = 0;
for(; i < s; ++i)
{
/* PySequence_GetItem returns new reference. */
PyObject* e = PySequence_GetItem(a, i);
l = list_new(l, newstr(PyString_AsString(e)));
Py_DECREF(e);
}
lol_add(inner->args, l);
}
}
}
result = evaluate_rule( rulename, inner );
frame_free( inner );
}
/** Accepts three arguments: module name, rule name and Python callable.
Creates bjam rule with the specified name in the specified module,
which will invoke the Python callable.
*/
PyObject*
bjam_import_rule(PyObject* self, PyObject* args)
{
char* module;
char* rule;
PyObject* func;
module_t* m;
RULE* r;
if (!PyArg_ParseTuple(args, "ssO:import_rule", &module, &rule, &func))
return NULL;
if (!PyCallable_Check(func))
return NULL;
m = bindmodule(module);
r = bindrule(rule, m);
/* Make pFunc owned */
Py_INCREF(func);
r->python_function = func;
return Py_None;
}
#endif

View File

@@ -44,6 +44,7 @@ LIST *builtin_native_rule( PARSE *parse, FRAME *frame );
LIST *builtin_user_module( PARSE *parse, FRAME *frame );
LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame );
LIST *builtin_check_if_file( PARSE *parse, FRAME *frame );
LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame );
void backtrace( FRAME *frame );

View File

@@ -889,6 +889,106 @@ void profile_dump()
}
}
static int python_instance_number = 0;
RULE *
enter_rule( char *rulename, module_t *target_module );
#ifdef HAVE_PYTHON
static LIST*
call_python_function(RULE* r, FRAME* frame)
{
LIST* result = 0;
PyObject* arguments = PyTuple_New(frame->args->count);
int i ;
PyObject* py_result;
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);
/* Steals reference to 'v' */
PyList_Append(arg, v);
}
/* Steals reference to 'arg' */
PyTuple_SetItem(arguments, i, arg);
}
py_result = PyObject_CallObject(r->python_function, arguments);
Py_DECREF(arguments);
if (py_result != NULL) {
if (PyList_Check(py_result)) {
int size = PyList_Size(py_result);
int i;
for(i = 0; i < size; ++i)
{
PyObject* item = PyList_GetItem(py_result, i);
if (PyString_Check(item))
{
result = list_new(result,
newstr(PyString_AsString(item)));
}
else
{
fprintf(stderr, "Non-string object returned by Python call\n");
}
}
}
else if (PyInstance_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);
}
else if (py_result == Py_None)
{
result = L0;
}
else
{
fprintf(stderr, "Non-list object returned by Python call\n");
}
Py_DECREF(py_result);
}
else {
PyErr_Print();
fprintf(stderr,"Call failed\n");
}
return result;
}
#endif
/*
* evaluate_rule() - execute a rule invocation
*/
@@ -925,6 +1025,13 @@ evaluate_rule(
rulename = l->string;
rule = bindrule( l->string, frame->module );
#ifdef HAVE_PYTHON
if (rule->python_function)
{
return call_python_function(rule, frame);
}
#endif
/* drop the rule name */
l = list_pop_front( l );

View File

@@ -196,6 +196,14 @@ static void run_unit_tests()
}
#endif
#ifdef HAVE_PYTHON
extern PyObject*
bjam_call(PyObject *self, PyObject *args);
extern PyObject*
bjam_import_rule(PyObject* self, PyObject* args);
#endif
int main( int argc, char **argv, char **arg_environ )
{
int n;
@@ -211,6 +219,23 @@ int main( int argc, char **argv, char **arg_environ )
InitGraf(&qd.thePort);
# endif
#ifdef HAVE_PYTHON
Py_Initialize();
{
static PyMethodDef BjamMethods[] = {
{"call", bjam_call, METH_VARARGS,
"Call the specified bjam rule."},
{"import_rule", bjam_import_rule, METH_VARARGS,
"Imports Python callable to bjam."},
{NULL, NULL, 0, NULL}
};
Py_InitModule("bjam", BjamMethods);
}
#endif
argc--, argv++;
if( ( n = getoptions( argc, argv, "-:d:j:f:gs:t:ano:qv", optv ) ) < 0 )
@@ -463,5 +488,10 @@ int main( int argc, char **argv, char **arg_environ )
if( globs.cmdout )
fclose( globs.cmdout );
#ifdef HAVE_PYTHON
Py_Finalize();
#endif
return status ? EXITBAD : EXITOK;
}

View File

@@ -37,6 +37,11 @@
#ifndef JAM_H_VP_2003_08_01
#define JAM_H_VP_2003_08_01
#ifdef HAVE_PYTHON
#include <Python.h>
#endif
/*
* VMS, OPENVMS
*/

View File

@@ -82,6 +82,9 @@ enter_rule( char *rulename, module_t *target_module )
r->arguments = 0;
r->exported = 0;
r->module = target_module;
#ifdef HAVE_PYTHON
r->python_function = 0;
#endif
}
return r;
}

View File

@@ -87,6 +87,9 @@ struct _rule {
* appear in the global module and be
* automatically imported into other modules
*/
#ifdef HAVE_PYTHON
PyObject* python_function;
#endif
};
/* ACTIONS - a chain of ACTIONs */

View File

@@ -17,6 +17,11 @@ VERSION = 3$(.)1$(.)10 ;
RELEASE = 1 ;
LICENSE = 1_0 ;
HAVE_PYTHON = 0 ;
PYTHON_INCUDES = /usr/include/python2.3 ;
PYTHON_LIB = -lpython2.3 ;
# Generate development debug binaries?
if --debug in $(ARGV)
{
@@ -326,6 +331,16 @@ if $(VMS)
}
--defs += YYSTACKSIZE=5000 ;
if $(HAVE_PYTHON) = 1
{
--defs += HAVE_PYTHON ;
--flags += -I$(PYTHON_INCUDES) ;
--flags += -Wno-long-long ;
--libs += $(PYTHON_LIB) ;
}
# The basic symbolic targets...
NOTFILE all clean dist ;
ALWAYS clean ;

View File

@@ -22,6 +22,7 @@
# include "hdrmacro.h"
# include "compile.h"
# include "native.h"
# include "variable.h"
# include <ctype.h>
/*
@@ -287,8 +288,14 @@ load_builtins()
builtin_check_if_file, 0, args );
}
#ifdef HAVE_PYTHON
{
char * args[] = { "python-module", ":", "function", ":",
"jam-module", ":", "rule-name", 0 };
bind_builtin( "PYTHON_IMPORT_RULE",
builtin_python_import_rule, 0, args );
}
#endif
# ifdef OS_NT
{
@@ -1238,6 +1245,92 @@ LIST *builtin_check_if_file( PARSE *parse, FRAME *frame )
}
#ifdef HAVE_PYTHON
LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame )
{
static int first_time = 1;
char* python_module = lol_get( frame->args, 0 )->string;
char* python_function = lol_get( frame->args, 1 )->string;
char* jam_module = lol_get( frame->args, 2 )->string;
char* jam_rule = lol_get( frame->args, 3 )->string;
PyObject *pName, *pModule, *pDict, *pFunc;
if (first_time)
{
/* At the first invocation, we add the value of the
global EXTRA_PYTHONPATH to the sys.path Python
variable.
*/
LIST* extra = 0;
module_t* outer_module = frame->module;
first_time = 0;
if ( outer_module != root_module())
{
exit_module( outer_module );
enter_module( root_module());
}
extra = var_get("EXTRA_PYTHONPATH");
if ( outer_module != root_module())
{
exit_module( root_module());
enter_module( outer_module );
}
for(; extra; extra = extra->next)
{
string buf[1];
string_new(buf);
string_append(buf, "import sys\nsys.path.append(\"");
string_append(buf, extra->string);
string_append(buf, "\")\n");
PyRun_SimpleString(buf->value);
string_free(buf);
}
}
pName = PyString_FromString(python_module);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, python_function);
if (pFunc && PyCallable_Check(pFunc)) {
module_t* m = bindmodule(jam_module);
RULE* r = bindrule( jam_rule, m );
/* Make pFunc owned */
Py_INCREF(pFunc);
r->python_function = pFunc;
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", python_function);
}
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", python_module);
}
return L0;
}
#endif
void lol_build( LOL* lol, char** elements )
{
LIST* l = L0;
@@ -1261,3 +1354,92 @@ void lol_build( LOL* lol, char** elements )
lol_add( lol, l );
}
#ifdef HAVE_PYTHON
/** Calls the bjam rule specified by name passed in 'args'.
The name is looked up in context of bjam's 'python_interface'
module. Returns the list of string retured by the rule.
*/
PyObject*
bjam_call(PyObject* self, PyObject* args)
{
FRAME inner[1];
LIST *result;
PARSE *p;
char* rulename;
/* Build up the list of arg lists */
frame_init( inner );
inner->prev = 0;
inner->prev_user = 0;
inner->module = bindmodule("python_interface");
inner->procedure = 0;
/* Extract the rule name and arguments from 'args' */
/* PyTuple_GetItem returns borrowed reference */
rulename = PyString_AsString(PyTuple_GetItem(args, 0));
{
int i = 1;
int size = PyTuple_Size(args);
for( ; i < size; ++i) {
PyObject* a = PyTuple_GetItem(args, i);
if (PyString_Check(a))
{
lol_add(inner->args,
list_new(0, newstr(PyString_AsString(a))));
}
else if (PySequence_Check(a))
{
LIST* l = 0;
int s = PySequence_Size(a);
int i = 0;
for(; i < s; ++i)
{
/* PySequence_GetItem returns new reference. */
PyObject* e = PySequence_GetItem(a, i);
l = list_new(l, newstr(PyString_AsString(e)));
Py_DECREF(e);
}
lol_add(inner->args, l);
}
}
}
result = evaluate_rule( rulename, inner );
frame_free( inner );
}
/** Accepts three arguments: module name, rule name and Python callable.
Creates bjam rule with the specified name in the specified module,
which will invoke the Python callable.
*/
PyObject*
bjam_import_rule(PyObject* self, PyObject* args)
{
char* module;
char* rule;
PyObject* func;
module_t* m;
RULE* r;
if (!PyArg_ParseTuple(args, "ssO:import_rule", &module, &rule, &func))
return NULL;
if (!PyCallable_Check(func))
return NULL;
m = bindmodule(module);
r = bindrule(rule, m);
/* Make pFunc owned */
Py_INCREF(func);
r->python_function = func;
return Py_None;
}
#endif

View File

@@ -44,6 +44,7 @@ LIST *builtin_native_rule( PARSE *parse, FRAME *frame );
LIST *builtin_user_module( PARSE *parse, FRAME *frame );
LIST *builtin_nearest_user_location( PARSE *parse, FRAME *frame );
LIST *builtin_check_if_file( PARSE *parse, FRAME *frame );
LIST *builtin_python_import_rule( PARSE *parse, FRAME *frame );
void backtrace( FRAME *frame );

View File

@@ -889,6 +889,106 @@ void profile_dump()
}
}
static int python_instance_number = 0;
RULE *
enter_rule( char *rulename, module_t *target_module );
#ifdef HAVE_PYTHON
static LIST*
call_python_function(RULE* r, FRAME* frame)
{
LIST* result = 0;
PyObject* arguments = PyTuple_New(frame->args->count);
int i ;
PyObject* py_result;
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);
/* Steals reference to 'v' */
PyList_Append(arg, v);
}
/* Steals reference to 'arg' */
PyTuple_SetItem(arguments, i, arg);
}
py_result = PyObject_CallObject(r->python_function, arguments);
Py_DECREF(arguments);
if (py_result != NULL) {
if (PyList_Check(py_result)) {
int size = PyList_Size(py_result);
int i;
for(i = 0; i < size; ++i)
{
PyObject* item = PyList_GetItem(py_result, i);
if (PyString_Check(item))
{
result = list_new(result,
newstr(PyString_AsString(item)));
}
else
{
fprintf(stderr, "Non-string object returned by Python call\n");
}
}
}
else if (PyInstance_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);
}
else if (py_result == Py_None)
{
result = L0;
}
else
{
fprintf(stderr, "Non-list object returned by Python call\n");
}
Py_DECREF(py_result);
}
else {
PyErr_Print();
fprintf(stderr,"Call failed\n");
}
return result;
}
#endif
/*
* evaluate_rule() - execute a rule invocation
*/
@@ -925,6 +1025,13 @@ evaluate_rule(
rulename = l->string;
rule = bindrule( l->string, frame->module );
#ifdef HAVE_PYTHON
if (rule->python_function)
{
return call_python_function(rule, frame);
}
#endif
/* drop the rule name */
l = list_pop_front( l );

View File

@@ -196,6 +196,14 @@ static void run_unit_tests()
}
#endif
#ifdef HAVE_PYTHON
extern PyObject*
bjam_call(PyObject *self, PyObject *args);
extern PyObject*
bjam_import_rule(PyObject* self, PyObject* args);
#endif
int main( int argc, char **argv, char **arg_environ )
{
int n;
@@ -211,6 +219,23 @@ int main( int argc, char **argv, char **arg_environ )
InitGraf(&qd.thePort);
# endif
#ifdef HAVE_PYTHON
Py_Initialize();
{
static PyMethodDef BjamMethods[] = {
{"call", bjam_call, METH_VARARGS,
"Call the specified bjam rule."},
{"import_rule", bjam_import_rule, METH_VARARGS,
"Imports Python callable to bjam."},
{NULL, NULL, 0, NULL}
};
Py_InitModule("bjam", BjamMethods);
}
#endif
argc--, argv++;
if( ( n = getoptions( argc, argv, "-:d:j:f:gs:t:ano:qv", optv ) ) < 0 )
@@ -463,5 +488,10 @@ int main( int argc, char **argv, char **arg_environ )
if( globs.cmdout )
fclose( globs.cmdout );
#ifdef HAVE_PYTHON
Py_Finalize();
#endif
return status ? EXITBAD : EXITOK;
}

View File

@@ -37,6 +37,11 @@
#ifndef JAM_H_VP_2003_08_01
#define JAM_H_VP_2003_08_01
#ifdef HAVE_PYTHON
#include <Python.h>
#endif
/*
* VMS, OPENVMS
*/

View File

@@ -82,6 +82,9 @@ enter_rule( char *rulename, module_t *target_module )
r->arguments = 0;
r->exported = 0;
r->module = target_module;
#ifdef HAVE_PYTHON
r->python_function = 0;
#endif
}
return r;
}

View File

@@ -87,6 +87,9 @@ struct _rule {
* appear in the global module and be
* automatically imported into other modules
*/
#ifdef HAVE_PYTHON
PyObject* python_function;
#endif
};
/* ACTIONS - a chain of ACTIONs */