[php] Fix handling of multi-module cases

Look up unknown base classes using SWIG_MangledTypeQueryModule().

Revert to using SWIG_TypeCheck() instead of SWIG_TypeCheckStruct()
as the latter doesn't seem to work for this case (at least for PHP
right now).

Add mod_runme.php as a regression test for this.

Adjust the PHP test harness not to set up reflection for the module
unless it's actually needed for a testcase.  Currently the approach
to find the module name doesn't work for multi-module testcases.

See #2126
This commit is contained in:
Olly Betts 2022-10-18 10:28:17 +13:00
commit 747a6a264f
6 changed files with 56 additions and 23 deletions

View file

@ -1215,6 +1215,9 @@ php_cpp: $(SRCDIR_SRCS)
php_run:
$(RUNTOOL) $(PHP) -n -d extension_dir=. -d extension=$(PHP_EXTENSION) -d display_errors=stderr -r 'set_error_handler(function($$n,$$s,$$f,$$l){if($$f!==Null){print$$f;if($$l!==Null)print":$$l";print": ";}print"$$s\n";exit(1);});if(strlen($$argv[1]))include($$argv[1]);' '$(PHP_SCRIPT)' $(RUNPIPE)
php_run_multi:
$(RUNTOOL) $(PHP) -n -d extension_dir=. `while read e ; do echo ' -d extension=$(TARGETPREFIX)'"$$e"'@PHP_SO@' ; done < $(PHP_EXTENSION_LIST)` -d display_errors=stderr -r 'set_error_handler(function($$n,$$s,$$f,$$l){if($$f!==Null){print$$f;if($$l!==Null)print":$$l";print": ";}print"$$s\n";exit(1);});if(strlen($$argv[1]))include($$argv[1]);' '$(PHP_SCRIPT)' $(RUNPIPE)
# -----------------------------------------------------------------
# Version display
# -----------------------------------------------------------------

View file

@ -57,10 +57,18 @@ missingtests: missingcpptests missingctests
+$(swig_and_compile_c)
+$(run_testcase)
# Trying to load the modules for imports.multicpptest fails with:
#
# Warning: Function registration failed - duplicate name - global_test in Unknown on line 0
# Segmentation fault
#
# This was previously hidden because we didn't even try to load the modules for
# .multicpptest testcases, so for now just do the parts of the test we did
# before. FIXME: Fix this!
%.multicpptest:
$(setup)
+$(swig_and_compile_multi_cpp)
+$(run_testcase)
+[ "$*" = "imports" ] || $(run_multi_testcase)
# Smart target
%.test:
@ -72,14 +80,23 @@ missingtests: missingcpptests missingctests
$(MAKE) $*.multicpptest
# Runs the testcase. Tries to run testcase_runme.php, and if that's not found,
# at least test that the module loads without errors, except for multicpptests.
# at least test that the module loads without errors.
run_testcase = \
if [ -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION=$(TARGETPREFIX)$*@PHP_SO@ PHP_SCRIPT=$(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) RUNTOOL='$(RUNTOOL)' php_run; \
elif [ ! -f $(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list ]; then \
else \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION=$(TARGETPREFIX)$*@PHP_SO@ PHP_SCRIPT= RUNTOOL='$(RUNTOOL)' php_run; \
fi
# Runs a multicpptest testcase. Tries to run testcase_runme.php, and if that's
# not found, at least test that the modules load without errors.
run_multi_testcase = \
if [ -f $(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) ]; then \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION_LIST=$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list PHP_SCRIPT=$(SCRIPTDIR)/$(SCRIPTPREFIX)$*$(SCRIPTSUFFIX) RUNTOOL='$(RUNTOOL)' php_run_multi; \
else \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile PHP_EXTENSION_LIST=$(top_srcdir)/$(EXAMPLES)/$(TEST_SUITE)/$*.list PHP_SCRIPT= RUNTOOL='$(RUNTOOL)' php_run_multi; \
fi
# Clean: remove the generated PHP-specific files
%.clean:
@rm -f php_$*.h

View file

@ -0,0 +1,9 @@
<?php
require "tests.php";
$c = new C();
$d = new D();
$d->DoSomething($c);
check::done();

View file

@ -9,18 +9,19 @@ class check {
private static $_werror = false;
// This is called automatically at the end of this file.
static function init() {
foreach(get_included_files() as $f) {
$module_name = preg_filter('/.*\/([^\/]+)_runme\.php$/', '\1', $f);
if ($module_name !== null) break;
static function get_extension() {
if (self::$_extension === null) {
foreach(get_included_files() as $f) {
$module_name = preg_filter('/.*\/([^\/]+)_runme\.php$/', '\1', $f);
if ($module_name !== null) break;
}
if ($module_name === null) {
print("Failed to determine module name from get_included_files()\n");
exit(1);
}
self::$_extension = new ReflectionExtension($module_name);
}
if ($module_name === null) {
print("Failed to determine module name from get_included_files()\n");
exit(1);
}
self::$_extension = new ReflectionExtension($module_name);
return self::$_extension;
}
static function werror($v) {
@ -92,7 +93,7 @@ class check {
if (! is_array($classes)) $classes=array($classes);
$message=array();
$missing=array();
$extra = array_flip(array_filter(self::$_extension->getClassNames(),
$extra = array_flip(array_filter(self::get_extension()->getClassNames(),
function ($e) { return !preg_match('/^SWIG\\\\/', $e); }));
foreach($classes as $class) {
if (! class_exists($class)) $missing[]=$class;
@ -109,7 +110,7 @@ class check {
if (! is_array($functions)) $functions=array($functions);
$message=array();
$missing=array();
$extra = self::$_extension->getFunctions();
$extra = self::get_extension()->getFunctions();
foreach ($functions as $func) {
if (! function_exists($func)) $missing[]=$func;
else unset($extra[$func]);
@ -127,7 +128,7 @@ class check {
if (! is_array($globals)) $globals=array($globals);
$message=array();
$missing=array();
$extra = self::$_extension->getFunctions();
$extra = self::get_extension()->getFunctions();
foreach ($globals as $glob) {
if (! function_exists($glob . "_get") && ! function_exists($glob . "_set")) $missing[]=$glob;
else {
@ -149,7 +150,7 @@ class check {
if (! is_array($constants)) $constants=array($constants);
$message=array();
$missing=array();
$extra = self::$_extension->getConstants();
$extra = self::get_extension()->getConstants();
unset($extra['swig_runtime_data_type_pointer']);
foreach($constants as $constant) {
if (! defined($constant)) $missing[]=$constant;
@ -213,5 +214,3 @@ class check {
# print $_SERVER[argv][0]." ok\n";
}
}
check::init();

View file

@ -193,7 +193,7 @@ SWIG_ConvertPtrAndOwn(zval *z, void **ptr, swig_type_info *ty, int flags, swig_o
/* They don't care about the target type, so just pass on the pointer! */
*ptr = value->ptr;
} else {
swig_cast_info *tc = SWIG_TypeCheckStruct(value->type, ty);
swig_cast_info *tc = SWIG_TypeCheck(value->type->name, ty);
if (tc) {
int newmemory = 0;
*ptr = SWIG_TypeCast(tc, value->ptr, &newmemory);

View file

@ -1836,13 +1836,18 @@ public:
base_class = NewString("Exception");
}
if (Equal(base_class, "Exception")) {
if (!base_class) {
Printf(s_oinit, " SWIG_Php_ce_%s = zend_register_internal_class(&internal_ce);\n", class_name);
} else if (Equal(base_class, "Exception")) {
Printf(s_oinit, " SWIG_Php_ce_%s = zend_register_internal_class_ex(&internal_ce, zend_ce_exception);\n", class_name);
} else if (is_class_wrapped(base_class)) {
Printf(s_oinit, " SWIG_Php_ce_%s = zend_register_internal_class_ex(&internal_ce, SWIG_Php_ce_%s);\n", class_name, base_class);
Setattr(php_parent_class, class_name, base_class);
} else {
Printf(s_oinit, " SWIG_Php_ce_%s = zend_register_internal_class(&internal_ce);\n", class_name);
Printf(s_oinit, " {\n");
Printf(s_oinit, " swig_type_info *type_info = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, \"_p_%s\");\n", base_class);
Printf(s_oinit, " SWIG_Php_ce_%s = zend_register_internal_class_ex(&internal_ce, (zend_class_entry*)(type_info ? type_info->clientdata : NULL));\n", class_name);
Printf(s_oinit, " }\n");
}
if (Getattr(n, "abstracts") && !GetFlag(n, "feature:notabstract")) {