[PHP] Add support for PHP7.

PHP5's C extension API has changed substantially so you need to use
-php7 to specify you want PHP7 compatible wrappers.
Fixes https://github.com/swig/swig/issues/571
This commit is contained in:
Olly Betts 2016-11-30 13:05:59 +13:00
commit 1169874f59
202 changed files with 11575 additions and 719 deletions

View file

@ -43,7 +43,7 @@
#include <errno.h>
static const char *usage = "\
PHP Options (available with -php)\n\
PHP Options (available with -php7)\n\
-noproxy - Don't generate proxy classes.\n\
-prefix <prefix> - Prepend <prefix> to all class names in PHP wrappers\n\
\n";
@ -152,14 +152,14 @@ static void SwigPHP_emit_resource_registrations() {
human_name = Getattr(class_node, "name");
// Do we have a known destructor for this type?
if (destructor) {
Printf(s_wrappers, " %s(rsrc, SWIGTYPE%s->name TSRMLS_CC);\n", destructor, key);
Printf(s_wrappers, " %s(res, SWIGTYPE%s->name);\n", destructor, key);
} else {
Printf(s_wrappers, " /* No destructor for class %s */\n", human_name);
Printf(s_wrappers, " efree(rsrc->ptr);\n");
Printf(s_wrappers, " efree(res->ptr);\n");
}
} else {
Printf(s_wrappers, " /* No destructor for simple type %s */\n", key);
Printf(s_wrappers, " efree(rsrc->ptr);\n");
Printf(s_wrappers, " efree(res->ptr);\n");
}
// close function
@ -170,7 +170,7 @@ static void SwigPHP_emit_resource_registrations() {
// register with php
Printf(s_oinit, "le_swig_%s=zend_register_list_destructors_ex"
"(_wrap_destroy%s,NULL,(char *)(SWIGTYPE%s->name),module_number);\n", key, key, key);
"(_wrap_destroy%s, NULL, SWIGTYPE%s->name, module_number);\n", key, key, key);
// store php type in class struct
Printf(s_oinit, "SWIG_TypeClientData(SWIGTYPE%s,&le_swig_%s);\n", key, key);
@ -180,23 +180,6 @@ static void SwigPHP_emit_resource_registrations() {
}
class PHP : public Language {
String *emit_action(Node *n) {
// Adjust wrap:action to add TSRMLS_CC.
String * action = Getattr(n, "wrap:action");
if (action) {
char * p = Strstr(action, "Swig::DirectorPureVirtualException::raise(\"");
if (p) {
p += strlen("Swig::DirectorPureVirtualException::raise(\"");
p = strchr(p, '"');
if (p) {
++p;
Insert(action, (int)(p - Char(action)), " TSRMLS_CC");
}
}
}
return ::emit_action(n);
}
public:
PHP() {
director_language = 1;
@ -225,25 +208,11 @@ public:
Swig_mark_arg(i);
} else if (strcmp(argv[i], "-help") == 0) {
fputs(usage, stdout);
} else if (strcmp(argv[i], "-make") == 0 ||
strcmp(argv[i], "-withc") == 0 ||
strcmp(argv[i], "-withcxx") == 0) {
Printf(stderr, "*** %s is no longer supported.\n", argv[i]);
SWIG_exit(EXIT_FAILURE);
} else if (strcmp(argv[i], "-phpfull") == 0 ||
strcmp(argv[i], "-withlibs") == 0 ||
strcmp(argv[i], "-withincs") == 0) {
Printf(stderr, "*** %s is no longer supported.\n*** We recommend building as a dynamically loadable module.\n", argv[i]);
SWIG_exit(EXIT_FAILURE);
} else if (strcmp(argv[i], "-dlname") == 0) {
Printf(stderr, "*** -dlname is no longer supported.\n*** If you want to change the module name, use -module instead.\n");
SWIG_exit(EXIT_FAILURE);
}
}
Preprocessor_define("SWIGPHP 1", 0);
// SWIGPHP5 is deprecated, and no longer documented.
Preprocessor_define("SWIGPHP5 1", 0);
Preprocessor_define("SWIGPHP7 1", 0);
SWIG_typemap_lang("php");
SWIG_config_file("php.swg");
allow_overloading();
@ -267,7 +236,7 @@ public:
}
/* Set comparison with null for ConstructorToFunction */
setSubclassInstanceCheck(NewString("$arg->type != IS_NULL"));
setSubclassInstanceCheck(NewString("Z_TYPE_P($arg) != IS_NULL"));
/* Initialize all of the output files */
String *outfile = Getattr(n, "outfile");
@ -402,9 +371,9 @@ public:
* which has to be dynamically generated as it depends on the module name.
*/
Append(s_header, "#ifdef __GNUC__\n");
Append(s_header, "static void SWIG_FAIL(TSRMLS_D) __attribute__ ((__noreturn__));\n");
Append(s_header, "static void SWIG_FAIL(void) __attribute__ ((__noreturn__));\n");
Append(s_header, "#endif\n\n");
Append(s_header, "static void SWIG_FAIL(TSRMLS_D) {\n");
Append(s_header, "static void SWIG_FAIL(void) {\n");
Append(s_header, " zend_error(SWIG_ErrorCode(), \"%s\", SWIG_ErrorMsg());\n");
// zend_error() should never return with the parameters we pass, but if it
// does, we really don't want to let SWIG_FAIL() return. This also avoids
@ -420,38 +389,36 @@ public:
Printf(s_header, "static void %s_destroy_globals(zend_%s_globals * globals) { (void)globals; }\n", module, module);
Printf(s_header, "\n");
Printf(s_header, "static void SWIG_ResetError(TSRMLS_D) {\n");
Printf(s_header, "static void SWIG_ResetError(void) {\n");
Printf(s_header, " SWIG_ErrorMsg() = default_error_msg;\n");
Printf(s_header, " SWIG_ErrorCode() = default_error_code;\n");
Printf(s_header, "}\n");
Append(s_header, "\n");
Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_alter_newobject) {\n", module);
Append(s_header, " zval **args[2];\n");
Append(s_header, " zval args[2];\n");
Append(s_header, " swig_object_wrapper *value;\n");
Append(s_header, " int type;\n");
Append(s_header, "\n");
Append(s_header, " SWIG_ResetError(TSRMLS_C);\n");
Append(s_header, " SWIG_ResetError();\n");
Append(s_header, " if(ZEND_NUM_ARGS() != 2 || zend_get_parameters_array_ex(2, args) != SUCCESS) {\n");
Append(s_header, " WRONG_PARAM_COUNT;\n");
Append(s_header, " }\n");
Append(s_header, "\n");
Append(s_header, " value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n");
Append(s_header, " value->newobject = zval_is_true(*args[1]);\n");
Append(s_header, " value = (swig_object_wrapper *) Z_RES_VAL(args[0]);\n");
Append(s_header, " value->newobject = zval_is_true(&args[1]);\n");
Append(s_header, "\n");
Append(s_header, " return;\n");
Append(s_header, "}\n");
Printf(s_header, "ZEND_NAMED_FUNCTION(_wrap_swig_%s_get_newobject) {\n", module);
Append(s_header, " zval **args[1];\n");
Append(s_header, " zval args[1];\n");
Append(s_header, " swig_object_wrapper *value;\n");
Append(s_header, " int type;\n");
Append(s_header, "\n");
Append(s_header, " SWIG_ResetError(TSRMLS_C);\n");
Append(s_header, " SWIG_ResetError();\n");
Append(s_header, " if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, args) != SUCCESS) {\n");
Append(s_header, " WRONG_PARAM_COUNT;\n");
Append(s_header, " }\n");
Append(s_header, "\n");
Append(s_header, " value = (swig_object_wrapper *) zend_list_find((*args[0])->value.lval, &type);\n");
Append(s_header, " value = (swig_object_wrapper *) Z_RES_VAL(args[0]);\n");
Append(s_header, " RETVAL_LONG(value->newobject);\n");
Append(s_header, "\n");
Append(s_header, " return;\n");
@ -525,7 +492,7 @@ public:
Append(s_init, "#endif\n");
Printv(s_init, "zend_module_entry ", module, "_module_entry = {\n", NIL);
Printf(s_init, " STANDARD_MODULE_HEADER,\n");
Printf(s_init, " (char*)\"%s\",\n", module);
Printf(s_init, " \"%s\",\n", module);
Printf(s_init, " %s_functions,\n", module);
Printf(s_init, " PHP_MINIT(%s),\n", module);
Printf(s_init, " PHP_MSHUTDOWN(%s),\n", module);
@ -710,12 +677,12 @@ public:
Wrapper_add_local(f, "argc", "int argc");
Printf(tmp, "zval **argv[%d]", maxargs);
Printf(tmp, "zval argv[%d]", maxargs);
Wrapper_add_local(f, "argv", tmp);
Printf(f->code, "argc = ZEND_NUM_ARGS();\n");
Printf(f->code, "zend_get_parameters_array_ex(argc,argv);\n");
Printf(f->code, "zend_get_parameters_array_ex(argc, argv);\n");
Replaceall(dispatch, "$args", "self,args");
@ -723,7 +690,7 @@ public:
Printf(f->code, "SWIG_ErrorCode() = E_ERROR;\n");
Printf(f->code, "SWIG_ErrorMsg() = \"No matching function for overloaded '%s'\";\n", symname);
Printv(f->code, "SWIG_FAIL(TSRMLS_C);\n", NIL);
Printv(f->code, "SWIG_FAIL();\n", NIL);
Printv(f->code, "}\n", NIL);
Wrapper_print(f, s_wrappers);
@ -819,8 +786,8 @@ public:
if (num_arguments > 0) {
String *args = NewStringEmpty();
if (wrapperType == directorconstructor)
Wrapper_add_local(f, "arg0", "zval *arg0");
Printf(args, "zval **args[%d]", num_arguments);
Wrapper_add_local(f, "arg0", "zval * arg0");
Printf(args, "zval args[%d]", num_arguments);
Wrapper_add_local(f, "args", args);
Delete(args);
args = NULL;
@ -834,7 +801,7 @@ public:
// NOTE: possible we ignore this_ptr as a param for native constructor
Printf(f->code, "SWIG_ResetError(TSRMLS_C);\n");
Printf(f->code, "SWIG_ResetError();\n");
if (numopt > 0) { // membervariable wrappers do not have optional args
Wrapper_add_local(f, "arg_count", "int arg_count");
@ -851,7 +818,7 @@ public:
Printf(f->code, "WRONG_PARAM_COUNT;\n}\n\n");
}
if (wrapperType == directorconstructor)
Printf(f->code, "arg0 = *args[0];\n \n");
Printf(f->code, "arg0 = &args[0];\n \n");
/* Now convert from PHP to C variables */
// At this point, argcount if used is the number of deliberately passed args
@ -891,7 +858,7 @@ public:
}
if ((tm = Getattr(p, "tmap:in"))) {
Replaceall(tm, "$source", source);
Replaceall(tm, "$source", &source);
Replaceall(tm, "$target", ln);
Replaceall(tm, "$input", source);
Setattr(p, "emit:input", source);
@ -915,7 +882,7 @@ public:
if (is_member_director(n)) {
Wrapper_add_local(f, "upcall", "bool upcall = false");
Printf(f->code, "upcall = !Swig::Director::swig_is_overridden_method((char *)\"%s%s\", (char *)\"%s\" TSRMLS_CC);\n",
Printf(f->code, "upcall = !Swig::Director::swig_is_overridden_method(\"%s%s\", \"%s\");\n",
prefix, Swig_class_name(Swig_methodclass(n)), name);
}
@ -1006,7 +973,7 @@ public:
/* Error handling code */
Printf(f->code, "fail:\n");
Printv(f->code, cleanup, NIL);
Append(f->code, "SWIG_FAIL(TSRMLS_C);\n");
Append(f->code, "SWIG_FAIL();\n");
Printf(f->code, "}\n");
@ -1056,6 +1023,7 @@ public:
bool handle_as_overload = false;
String **arg_names;
String **arg_values;
unsigned char * byref;
// Method or static method or plain function.
const char *methodname = 0;
String *output = s_oowrappers;
@ -1196,7 +1164,8 @@ public:
}
arg_values = (String **) malloc(max_num_of_arguments * sizeof(String *));
if (!arg_values) {
byref = (unsigned char *) malloc(max_num_of_arguments);
if (!arg_values || !byref) {
/* FIXME: How should this be handled? The rest of SWIG just seems
* to not bother checking for malloc failing! */
fprintf(stderr, "Malloc failed!\n");
@ -1204,6 +1173,7 @@ public:
}
for (i = 0; i < max_num_of_arguments; ++i) {
arg_values[i] = NULL;
byref[i] = false;
}
Node *o;
@ -1223,6 +1193,7 @@ public:
continue;
}
assert(0 <= argno && argno < max_num_of_arguments);
byref[argno] = GetFlag(p, "tmap:in:byref");
String *&pname = arg_names[argno];
const char *pname_cstr = GetChar(p, "name");
// Just get rid of the C++ namespace part for now.
@ -1471,6 +1442,7 @@ public:
Printf(args, ",");
if (i || wrapperType == memberfn)
Printf(invoke, ",");
if (byref[i]) Printf(args, "&");
String *value = arg_values[i];
if (value) {
const char *v = Char(value);
@ -2290,15 +2262,15 @@ done:
Delete(director_ctor_code);
director_ctor_code = NewStringEmpty();
director_prot_ctor_code = NewStringEmpty();
Printf(director_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n");
Printf(director_prot_ctor_code, "if ( arg0->type == IS_NULL ) { /* not subclassed */\n");
Printf(director_ctor_code, "if (Z_TYPE_P(arg0) == IS_NULL) { /* not subclassed */\n");
Printf(director_prot_ctor_code, "if (Z_TYPE_P(arg0) == IS_NULL) { /* not subclassed */\n");
Printf(director_ctor_code, " %s = (%s *)new %s(%s);\n", Swig_cresult_name(), ctype, ctype, args);
Printf(director_prot_ctor_code, " SWIG_PHP_Error(E_ERROR, \"accessing abstract class or protected constructor\");\n", name, name, args);
if (i) {
Insert(args, 0, ", ");
}
Printf(director_ctor_code, "} else {\n %s = (%s *)new SwigDirector_%s(arg0 TSRMLS_CC%s);\n}\n", Swig_cresult_name(), ctype, sname, args);
Printf(director_prot_ctor_code, "} else {\n %s = (%s *)new SwigDirector_%s(arg0 TSRMLS_CC%s);\n}\n", Swig_cresult_name(), ctype, sname, args);
Printf(director_ctor_code, "} else {\n %s = (%s *)new SwigDirector_%s(arg0%s);\n}\n", Swig_cresult_name(), ctype, sname, args);
Printf(director_prot_ctor_code, "} else {\n %s = (%s *)new SwigDirector_%s(arg0%s);\n}\n", Swig_cresult_name(), ctype, sname, args);
Delete(args);
wrapperType = directorconstructor;
@ -2328,9 +2300,9 @@ done:
Wrapper *f = NewWrapper();
Printf(f->def, "/* This function is designed to be called by the zend list destructors */\n");
Printf(f->def, "/* to typecast and do the actual destruction */\n");
Printf(f->def, "static void %s(zend_rsrc_list_entry *rsrc, const char *type_name TSRMLS_DC) {\n", destructorname);
Printf(f->def, "static void %s(zend_resource *res, const char *type_name) {\n", destructorname);
Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) rsrc->ptr", NIL);
Wrapper_add_localv(f, "value", "swig_object_wrapper *value=(swig_object_wrapper *) res->ptr", NIL);
Wrapper_add_localv(f, "ptr", "void *ptr=value->ptr", NIL);
Wrapper_add_localv(f, "newobject", "int newobject=value->newobject", NIL);
@ -2348,7 +2320,7 @@ done:
Printf(f->code, " efree(value);\n");
Printf(f->code, " if (! newobject) return; /* can't delete it! */\n");
Printf(f->code, " arg1 = (%s)SWIG_ZTS_ConvertResourceData(ptr,type_name,SWIGTYPE%s TSRMLS_CC);\n", SwigType_lstr(pt, 0), SwigType_manglestr(pt));
Printf(f->code, " arg1 = (%s)SWIG_ConvertResourceData(ptr, type_name, SWIGTYPE%s);\n", SwigType_lstr(pt, 0), SwigType_manglestr(pt));
Printf(f->code, " if (! arg1) zend_error(E_ERROR, \"%s resource already free'd\");\n", Char(name));
Setattr(n, "wrap:name", destructorname);
@ -2360,7 +2332,7 @@ done:
Printf(f->code, "thrown:\n");
Append(f->code, "return;\n");
Append(f->code, "fail:\n");
Append(f->code, "SWIG_FAIL(TSRMLS_C);\n");
Append(f->code, "SWIG_FAIL();\n");
Printf(f->code, "}\n");
Wrapper_print(f, s_wrappers);
@ -2420,16 +2392,9 @@ done:
String *call;
String *basetype = Getattr(parent, "classtype");
// We put TSRMLS_DC after the self parameter in order to cope with
// any default parameters.
String *target = Swig_method_decl(0, decl, classname, parms, 0, 0);
const char * p = Char(target);
const char * comma = strchr(p, ',');
int ins = comma ? (int)(comma - p) : Len(target) - 1;
Insert(target, ins, " TSRMLS_DC");
call = Swig_csuperclass_call(0, basetype, superparms);
Printf(w->def, "%s::%s: %s, Swig::Director(self TSRMLS_CC) {", classname, target, call);
Printf(w->def, "%s::%s: %s, Swig::Director(self) {", classname, target, call);
Append(w->def, "}");
Delete(target);
Wrapper_print(w, f_directors);
@ -2439,14 +2404,7 @@ done:
/* constructor header */
{
// We put TSRMLS_DC after the self parameter in order to cope with
// any default parameters.
String *target = Swig_method_decl(0, decl, classname, parms, 0, 1);
const char * p = Char(target);
const char * comma = strchr(p, ',');
int ins = comma ? (int)(comma - p) : Len(target) - 1;
Insert(target, ins, " TSRMLS_DC");
Printf(f_directors_h, " %s;\n", target);
Delete(target);
}
@ -2531,8 +2489,6 @@ done:
Append(w->def, " {");
Append(declaration, ";\n");
Printf(w->code, "TSRMLS_FETCH_FROM_CTX(swig_zts_ctx);\n");
/* declare method return value
* if the return value is a reference or const reference, a specialized typemap must
* handle it, including declaration of c_result ($result).
@ -2553,7 +2509,7 @@ done:
Printf(w->code, "%s;\n", super_call);
Delete(super_call);
} else {
Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\" TSRMLS_CC);\n", SwigType_namestr(c_classname),
Printf(w->code, "Swig::DirectorPureVirtualException::raise(\"Attempted to invoke pure virtual method %s::%s\");\n", SwigType_namestr(c_classname),
SwigType_namestr(name));
}
} else {
@ -2568,7 +2524,6 @@ done:
Swig_typemap_attach_parms("directorargout", l, w);
Parm *p;
char source[256];
int outputs = 0;
if (!is_void)
@ -2592,16 +2547,11 @@ done:
if ((tm = Getattr(p, "tmap:directorin")) != 0) {
String *parse = Getattr(p, "tmap:directorin:parse");
if (!parse) {
sprintf(source, "obj%d", idx++);
String *input = NewStringf("&%s", source);
String *input = NewStringf("&args[%d]", idx++);
Setattr(p, "emit:directorinput", input);
Replaceall(tm, "$input", input);
Delete(input);
Replaceall(tm, "$owner", "0");
Printv(wrap_args, "zval ", source, ";\n", NIL);
Printf(wrap_args, "args[%d] = &%s;\n", idx - 1, source);
Printv(wrap_args, "INIT_ZVAL(", source, ");\n", NIL);
Printv(wrap_args, tm, "\n", NIL);
Putc('O', parse_args);
} else {
@ -2644,17 +2594,17 @@ done:
}
if (!idx) {
Printf(w->code, "zval **args = NULL;\n");
Printf(w->code, "zval *args = NULL;\n");
} else {
Printf(w->code, "zval *args[%d];\n", idx);
Printf(w->code, "zval args[%d];\n", idx);
}
Printf(w->code, "zval *%s, funcname;\n", Swig_cresult_name());
Append(w->code, "if (!swig_self) {\n");
Append(w->code, " SWIG_PHP_Error(E_ERROR, \"this pointer is NULL\");");
Append(w->code, "}\n\n");
Printf(w->code, "MAKE_STD_ZVAL(%s);\n", Swig_cresult_name());
// typemap_directorout testcase requires that 0 can be assigned to the
// variable named after the result of Swig_cresult_name(), so that can't
// be a zval - make it a pointer to one instead.
Printf(w->code, "zval swig_zval_result, swig_funcname;\n", Swig_cresult_name());
Printf(w->code, "zval *%s = &swig_zval_result;\n", Swig_cresult_name());
const char * funcname = GetChar(n, "sym:name");
Printf(w->code, "ZVAL_STRINGL(&funcname, (char *)\"%s\", %d, 0);\n", funcname, strlen(funcname));
Printf(w->code, "ZVAL_STRINGL(&swig_funcname, \"%s\", %d);\n", funcname, strlen(funcname));
/* wrap complex arguments to zvals */
Printv(w->code, wrap_args, NIL);
@ -2662,8 +2612,8 @@ done:
if (error_used_in_typemap) {
Append(w->code, "error = ");
}
Append(w->code, "call_user_function(EG(function_table), (zval**)&swig_self, &funcname,");
Printf(w->code, " %s, %d, args TSRMLS_CC);\n", Swig_cresult_name(), idx);
Append(w->code, "call_user_function(EG(function_table), &swig_self, &swig_funcname,");
Printf(w->code, " &swig_zval_result, %d, args);\n", idx);
if (tm) {
Printv(w->code, Str(tm), "\n", NIL);
@ -2715,8 +2665,6 @@ done:
}
}
Printf(w->code, "FREE_ZVAL(%s);\n", Swig_cresult_name());
Delete(parse_args);
Delete(cleanup);
Delete(outarg);
@ -2738,7 +2686,7 @@ done:
}
Append(w->code, "fail:\n");
Append(w->code, "SWIG_FAIL(TSRMLS_C);\n");
Append(w->code, "SWIG_FAIL();\n");
Append(w->code, "}\n");
// We expose protected methods via an extra public inline method which makes a straight call to the wrapped class' method
@ -2783,7 +2731,8 @@ static PHP *maininstance = 0;
// We use this function to be able to write out zend_register_list_destructor_ex
// lines for most things in the type table
// NOTE: it's a function NOT A PHP::METHOD
extern "C" void typetrace(const SwigType *ty, String *mangled, String *clientdata) {
extern "C" {
static void typetrace(const SwigType *ty, String *mangled, String *clientdata) {
Node *class_node;
if (!zend_types) {
zend_types = NewHash();
@ -2803,6 +2752,7 @@ extern "C" void typetrace(const SwigType *ty, String *mangled, String *clientdat
if (r_prevtracefunc)
(*r_prevtracefunc) (ty, mangled, (String *) clientdata);
}
}
/* -----------------------------------------------------------------------------
* new_swig_php() - Instantiate module
@ -2819,13 +2769,6 @@ static Language *new_swig_php() {
return maininstance;
}
extern "C" Language *swig_php4(void) {
Printf(stderr, "*** -php4 is no longer supported.\n"
"*** Either upgrade to PHP5 or use SWIG 1.3.36 or earlier.\n");
SWIG_exit(EXIT_FAILURE);
return NULL; // To avoid compiler warnings.
}
extern "C" Language *swig_php(void) {
return new_swig_php();
}