Changes Octave module loading behavior, so that modules can be safely loaded inside functions without first being loaded at the base level. (Basically the module is now always loaded in the base context, and then a local link to the module is created in the current context.) Added an example, module_load, to Examples/octave to test this behaviour in different ways. Tested examples work for octave 3.0.5, 3.2.4, and 3.4.0. (thanks to Karl Wette)

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@12793 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
Xavier Delacour 2011-08-31 20:50:59 +00:00
commit 3372c2ba62
12 changed files with 251 additions and 79 deletions

View file

@ -366,7 +366,9 @@ octave_cpp: $(SRCS)
OCTSCRIPT = runme.m
octave_run: $(OCTSCRIPT)
env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH OCTAVEPATH=$(srcdir):$$OCTAVEPATH $(OCTAVE) $(OCTSCRIPT) >/dev/null
for file in $(OCTSCRIPT); do \
env LD_LIBRARY_PATH=.:$$LD_LIBRARY_PATH OCTAVEPATH=$(srcdir):$$OCTAVEPATH $(OCTAVE) $$file >/dev/null || break; \
done
# -----------------------------------------------------------------
# Cleaning the octave examples

View file

@ -9,6 +9,7 @@ funcptr
funcptr2
functor
operator
module_load
pointer
reference
simple

View file

@ -0,0 +1,26 @@
TOP = ../..
SWIG = $(TOP)/../preinst-swig
SRCS = example.c
TARGET = example
INTERFACE = example.i
OCTSCRIPTS = \
runme_args.m \
runme_gl_func.m \
runme_gl_func_base.m \
runme_nogl_func.m \
runme_nogl_func_base.m
all::
$(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' octave
static::
$(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \
TARGET='myoctave' INTERFACE='$(INTERFACE)' octave_static
clean::
$(MAKE) -f $(TOP)/Makefile octave_clean
rm -f $(TARGET).m
check: all
$(MAKE) -f $(TOP)/Makefile OCTSCRIPT="$(OCTSCRIPTS)" octave_run

View file

@ -0,0 +1,9 @@
/* File : example.c */
#include "example.h"
int ivar = 47;
int ifunc() {
return ivar;
}

View file

@ -0,0 +1,5 @@
/* File: example.h */
extern int ivar;
int ifunc();

View file

@ -0,0 +1,9 @@
/* File : example.i */
%module example
%{
#include "example.h"
%}
extern "C" int ivar;
int ifunc();

View file

@ -0,0 +1,12 @@
# file: runme_args.m
# test module loading with arguments
# test help
example -help
assert(!isglobal("example"))
# load module with custom cvar
example -globals mycvar
assert(!isglobal("cvar"))
assert(mycvar.ivar == example.ifunc())

View file

@ -0,0 +1,21 @@
# file: runme_gl_func.m
# test whether module can be loaded
# in a function (global cvar)
# test that everything works from the base context
example
global cvar
assert(cvar.ivar == example.ifunc())
function func
example
global cvar
assert(cvar.ivar == example.ifunc())
endfunction
# test loading in a function
func
# test a second time to check everything works
func

View file

@ -0,0 +1,23 @@
# file: runme_gl_func_base.m
# test whether module can be loaded in a function
# before the base context (global cvar)
1;
function func
example
global cvar
assert(cvar.ivar == example.ifunc())
endfunction
# test loading in a function
func
# test a second time to check everything works
func
# test that everything works from the base context
example
global cvar
assert(cvar.ivar == example.ifunc())

View file

@ -0,0 +1,19 @@
# file: runme_nogl_func.m
# test whether module can be loaded
# in a function (no global cvar)
# test that everything works from the base context
example -noglobal
assert(example.cvar.ivar == example.ifunc())
function func
example -noglobal
assert(example.cvar.ivar == example.ifunc())
endfunction
# test loading in a function
func
# test a second time to check everything works
func

View file

@ -0,0 +1,21 @@
# file: runme_nogl_func_base.m
# test whether module can be loaded in a function
# before the base context (no global cvar)
1;
function func
example -noglobal
assert(example.cvar.ivar == example.ifunc())
endfunction
# test loading in a function
func
# test a second time to check everything works
func
# test that everything works from the base context
example -noglobal
assert(example.cvar.ivar == example.ifunc())

View file

@ -5,6 +5,7 @@
#include <octave/ov-fcn-handle.h>
#include <octave/Cell.h>
#include <octave/oct-map.h>
#include <octave/toplev.h>
%}
%insert(runtime) "swigrun.swg";
@ -18,103 +19,126 @@
static void SWIG_init_user(octave_swig_type* module_ns);
DEFUN_DLD (SWIG_name,args,nargout,SWIG_name_d) {
static bool already_init=false;
if (already_init)
return octave_value_list();
// parse command line
const char* usage="usage: " SWIG_name_d " [-global|-noglobal] [-globals <name>]";
bool global_load=SWIG_global_load;
std::string global_name=SWIG_global_name;
for (int j=0;j<args.length();++j)
if (args(j).is_string()) {
if (args(j).string_value()=="-help") {
std::cout << usage << std::endl;
return octave_value_list();
} else if (args(j).string_value()=="-global") {
global_load = true;
} else if (args(j).string_value()=="-noglobal") {
global_load = false;
} else if (args(j).string_value()=="-globals") {
if (j+1<args.length()&&args(j+1).is_string()) {
global_name = args(j+1).string_value();
++j;
static bool already_init=false;
static octave_swig_type* module_ns=0;
// if module not already loaded
if (!already_init) {
// parse command line
const char* usage="usage: " SWIG_name_d " [-global|-noglobal] [-globals <name>]";
bool global_load=SWIG_global_load;
std::string global_name=SWIG_global_name;
for (int j=0;j<args.length();++j)
if (args(j).is_string()) {
if (args(j).string_value()=="-help") {
std::cout << usage << std::endl;
return octave_value_list();
} else if (args(j).string_value()=="-global") {
global_load = true;
} else if (args(j).string_value()=="-noglobal") {
global_load = false;
} else if (args(j).string_value()=="-globals") {
if (j+1<args.length()&&args(j+1).is_string()) {
global_name = args(j+1).string_value();
++j;
} else {
std::cerr << "error: " SWIG_name_d ": option '-globals' requires an argument." << std::endl;
std::cerr << usage << std::endl;
return octave_value_list();
}
} else {
std::cerr << "error: " SWIG_name_d ": option '-globals' requires an argument." << std::endl;
std::cerr << "error: " SWIG_name_d ": unrecognised argument '" << args(j).string_value() << "'." << std::endl;
std::cerr << usage << std::endl;
return octave_value_list();
}
} else {
std::cerr << "error: " SWIG_name_d ": unrecognised argument '" << args(j).string_value() << "'." << std::endl;
std::cerr << "error: " SWIG_name_d ": unrecognised non-string argument." << std::endl;
std::cerr << usage << std::endl;
return octave_value_list();
}
} else {
std::cerr << "error: " SWIG_name_d ": unrecognised non-string argument." << std::endl;
std::cerr << usage << std::endl;
if (!valid_identifier(global_name)) {
std::cerr << "error: " SWIG_name_d ": '" << global_name << "' is not a valid Octave identifier." << std::endl;
return octave_value_list();
}
if (!valid_identifier(global_name)) {
std::cerr << "error: " SWIG_name_d ": '" << global_name << "' is not a valid Octave identifier." << std::endl;
return octave_value_list();
}
already_init=true;
octave_swig_ref::register_type();
octave_swig_packed::register_type();
SWIG_InitializeModule(0);
SWIG_PropagateClientData();
install_builtin_function(swig_type,"swig_type",std::string());
install_builtin_function(swig_typequery,"swig_typequery",std::string());
install_builtin_function(swig_this,"swig_this",std::string());
install_builtin_function(swig_subclass,"subclass",std::string());
octave_swig_type* cvar_ns=new octave_swig_type;
for (int j=0;swig_globals[j].name;++j)
if (swig_globals[j].get_method)
cvar_ns->assign(swig_globals[j].name,&swig_globals[j]);
octave_swig_type* module_ns=new octave_swig_type(0, 0, 0, true);
module_ns->assign(global_name,Swig::swig_value_ref(cvar_ns));
for (int j=0;swig_globals[j].name;++j)
if (swig_globals[j].method)
module_ns->assign(swig_globals[j].name,&swig_globals[j]);
// * need better solution here; swig_type -> octave_class mapping is
// * really n-to-1, in some cases such as template partial spec, etc.
// * see failing tests.
for (int j=0;swig_types[j];++j)
if (swig_types[j]->clientdata) {
swig_octave_class* c=(swig_octave_class*)swig_types[j]->clientdata;
module_ns->assign(c->name,
Swig::swig_value_ref
(new octave_swig_type(0,swig_types[j])));
}
SWIG_init_user(module_ns);
SWIG_InstallOps(octave_swig_ref::static_type_id());
// the incref is necessary so install_global doesn't destroy module_ns,
// as it would if it installed something with the same name as the module.
module_ns->incref();
module_ns->install_global(global_load);
module_ns->decref();
already_init=true;
// load module in base frame
#if OCTAVE_API_VERSION_NUMBER<37
symbol_table *prev_sym_tab = curr_sym_tab;
curr_sym_tab = top_level_sym_tab;
#else
octave_call_stack::goto_base_frame();
#endif
octave_swig_ref::register_type();
octave_swig_packed::register_type();
SWIG_InitializeModule(0);
SWIG_PropagateClientData();
install_builtin_function(swig_type,"swig_type",std::string());
install_builtin_function(swig_typequery,"swig_typequery",std::string());
install_builtin_function(swig_this,"swig_this",std::string());
install_builtin_function(swig_subclass,"subclass",std::string());
octave_swig_type* cvar_ns=new octave_swig_type;
for (int j=0;swig_globals[j].name;++j)
if (swig_globals[j].get_method)
cvar_ns->assign(swig_globals[j].name,&swig_globals[j]);
module_ns=new octave_swig_type(0, 0, 0, true);
module_ns->assign(global_name,Swig::swig_value_ref(cvar_ns));
for (int j=0;swig_globals[j].name;++j)
if (swig_globals[j].method)
module_ns->assign(swig_globals[j].name,&swig_globals[j]);
// * need better solution here; swig_type -> octave_class mapping is
// * really n-to-1, in some cases such as template partial spec, etc.
// * see failing tests.
for (int j=0;swig_types[j];++j)
if (swig_types[j]->clientdata) {
swig_octave_class* c=(swig_octave_class*)swig_types[j]->clientdata;
module_ns->assign(c->name,
Swig::swig_value_ref
(new octave_swig_type(0,swig_types[j])));
}
SWIG_init_user(module_ns);
SWIG_InstallOps(octave_swig_ref::static_type_id());
// the incref is necessary so install_global doesn't destroy module_ns,
// as it would if it installed something with the same name as the module.
module_ns->incref();
module_ns->install_global(global_load);
module_ns->decref();
// create global variable containing module
set_global_value(SWIG_name_d,Swig::swig_value_ref(module_ns));
// return from base frame
#if OCTAVE_API_VERSION_NUMBER<37
curr_sym_tab = prev_sym_tab;
#else
octave_call_stack::pop();
#endif
#if OCTAVE_API_VERSION_NUMBER>=37
mlock();
#endif
} // !already_init
// link variable to module in current context
#if OCTAVE_API_VERSION_NUMBER<37
link_to_global_variable(curr_sym_tab->lookup(SWIG_name_d,true));
#else
symbol_table::varref(SWIG_name_d);
symbol_table::mark_global(SWIG_name_d);
#endif
set_global_value(SWIG_name_d,Swig::swig_value_ref(module_ns));
#if OCTAVE_API_VERSION_NUMBER>=37
mlock();
#endif
return octave_value_list();
}