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 OCTSCRIPT = runme.m
octave_run: $(OCTSCRIPT) 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 # Cleaning the octave examples

View file

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