From bc2a78fbab956fc87212da06f9dd5ef423aeeb40 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Mon, 14 May 2012 09:24:15 +0000 Subject: [PATCH] New Octave module loading behaviour - Use call syntax instead of cmdline to choose global/noglobal load: global: 'example;', noglobal: 'example = example;' - All functions loaded with Octave 'autoload' command; correctly loads .oct module and prevents segfault in Octave 3.0.5 - Functions no longer installed as global variables as well, so global operator dispatch now only looks for functions - Octave at-exit function created from string, not function, so no dependence on loaded .oct files at cleanup time - C at-exit function now immediately exits Octave (with correct status) to prevent seg-fault due to dodgy memory cleanup in some Octave versions - Documentation string for module loading function git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@13088 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Lib/octave/octrun.swg | 40 +----- Lib/octave/octruntime.swg | 258 +++++++++++++++++++------------------- Source/Modules/octave.cxx | 22 ++-- 3 files changed, 146 insertions(+), 174 deletions(-) diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg index 3ab6c7525..24dae705a 100644 --- a/Lib/octave/octrun.swg +++ b/Lib/octave/octrun.swg @@ -504,37 +504,9 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); rhs.members.clear(); } - void install_global(bool global_load) { - for (member_map::const_iterator it = members.begin(); it != members.end(); ++it) { - bool is_global_op = (it->first.substr(0, strlen(SWIG_op_prefix)) == SWIG_op_prefix); - bool is_func_defined = (it->second.first && it->second.first->method); - if (is_func_defined && (is_global_op || global_load)) { - install_builtin_function(it->second.first->method, it->first, - it->second.first->doc ? it->second.first->doc : std::string()); - } - octave_value global_val = is_global_op ? make_fcn_handle(it->first) : it->second.second; - if (global_val.is_defined() && (is_global_op || global_load)) { -#if OCTAVE_API_VERSION_NUMBER<37 - link_to_global_variable(curr_sym_tab->lookup(it->first, true)); -#else - symbol_table::varref(it->first); - symbol_table::mark_global(it->first); -#endif - set_global_value(it->first, global_val); - -#if OCTAVE_API_VERSION_NUMBER<37 - octave_swig_type *ost = Swig::swig_value_deref(global_val); - if (ost) { - const char* h = ost->help_text(); - if (h) { - symbol_record *sr = global_sym_tab->lookup (it->first, true); - sr->document(h); - } - } -#endif - } - } - } + typedef member_map::const_iterator swig_member_const_iterator; + swig_member_const_iterator swig_members_begin() { return members.begin(); } + swig_member_const_iterator swig_members_end() { return members.end(); } void *cast(swig_type_info *type, int *_own, int flags) { if (_own) @@ -835,10 +807,10 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); // we assume that SWIG_op_prefix-prefixed functions are installed in global namespace // (rather than any module namespace). - octave_value fcn = get_global_value(symbol, true); - if (!fcn.is_function() && !fcn.is_function_handle()) + octave_function *fcn = is_valid_function(symbol, std::string(), false); + if (!fcn) return false; - ret = fcn.subsref("(", std::list < octave_value_list > (1, args), 1); + ret = fcn->do_multi_index_op(1, args)(0); return true; } diff --git a/Lib/octave/octruntime.swg b/Lib/octave/octruntime.swg index 3aa866264..e23068438 100644 --- a/Lib/octave/octruntime.swg +++ b/Lib/octave/octruntime.swg @@ -1,11 +1,14 @@ %insert(runtime) %{ #include #include -#include -#include #include +#include +#include #include +#include +#include #include +#include %} %insert(runtime) "swigrun.swg"; @@ -18,9 +21,12 @@ static void SWIG_init_user(octave_swig_type* module_ns); -#if OCTAVE_API_VERSION_NUMBER>=37 -octave_value_list SWIG_atexit_func(const octave_value_list &args, int nargout); -#endif +SWIGINTERN void SWIG_Octave_InstallFunction(octave_function *octloadfcn, std::string name) { + octave_value_list args; + args.append(name); + args.append(octloadfcn->fcn_file_name()); + feval("autoload", args, 0); +} static const char *const subclass_usage = "-*- texinfo -*- \n\ @deftypefn {Loadable Function} {} subclass()\n\ @@ -114,87 +120,94 @@ DEFUN_DLD( swig_this, args, nargout, swig_this_usage ) { return octave_value(octave_uint64((unsigned long long) ost->swig_this())); } -DEFUN_DLD (SWIG_name,args,nargout,SWIG_name_d) { - - // determine if module is already loaded - bool already_load; -#if OCTAVE_API_VERSION_NUMBER<37 - { - symbol_record *rec = curr_sym_tab->lookup(SWIG_name_d); - already_load = (rec && rec->is_linked_to_global()); - } -#else - already_load = symbol_table::is_global(SWIG_name_d); +// workaround to prevent octave seg-faulting on exit: register at-exit +// function which exits octave immediately without trying to cleanup memory. +// definitely affects version 3.2.*, not sure about 3.3.*, seems to be +// fixed in version 3.4.* and above. can be turned on/off with macros. +#ifndef SWIG_OCTAVE_NO_SEGFAULT_HACK +#if 36 < OCTAVE_API_VERSION_NUMBER && OCTAVE_API_VERSION_NUMBER < 45 +#define SWIG_OCTAVE_SEGFAULT_HACK #endif - if (!already_load) { - - // parse command line - const char* usage="usage: " SWIG_name_d " [-global|-noglobal] [-globals {|.}]"; - bool global_load=SWIG_global_load; - std::string global_name=SWIG_global_name; - for (int j=0;j= 37 + octave_value_list eval_args; + eval_args.append("base"); + eval_args.append("function __swig_atexit__; " + " if mislocked() " + " clear -all; " + " else " + " mlock(); " + " endif; " + "endfunction; " + "__swig_atexit__; " + "atexit(\"__swig_atexit__\", false); " + "atexit(\"__swig_atexit__\")"); + feval("evalin", eval_args, 0); +#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(subclass,"subclass",std::string()); - + + octave_function *me = octave_call_stack::current(); + + SWIG_Octave_InstallFunction(me, "swig_type"); + SWIG_Octave_InstallFunction(me, "swig_typequery"); + SWIG_Octave_InstallFunction(me, "swig_this"); + SWIG_Octave_InstallFunction(me, "subclass"); + octave_swig_type* cvar_ns=0; - if (global_name != ".") { + if (SWIG_global_name != ".") { 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); - if (global_name != ".") { - module_ns->assign(global_name,Swig::swig_value_ref(cvar_ns)); + + module_ns=new octave_swig_type(0, 0, 0, true); + if (SWIG_global_name != ".") { + module_ns->assign(SWIG_global_name,Swig::swig_value_ref(cvar_ns)); } else { for (int j=0;swig_globals[j].name;++j) @@ -204,72 +217,63 @@ DEFUN_DLD (SWIG_name,args,nargout,SWIG_name_d) { 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. + + // * 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::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)); - -#if OCTAVE_API_VERSION_NUMBER>=37 - install_builtin_function(SWIG_atexit_func,"__swig_atexit_" SWIG_name_d "__",std::string()); - octave_add_atexit_function("__swig_atexit_" SWIG_name_d "__"); - octave_remove_atexit_function("__finish__"); -#endif - // return from base frame -#if OCTAVE_API_VERSION_NUMBER<37 - curr_sym_tab = prev_sym_tab; + SWIG_init_user(module_ns); + + SWIG_InstallOps(octave_swig_ref::static_type_id()); + +#if OCTAVE_API_VERSION_NUMBER < 37 + mlock(me->name()); #else - octave_call_stack::pop(); -#endif - -#if OCTAVE_API_VERSION_NUMBER>=37 mlock(); #endif - } // !already_load - - // 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 + } - return octave_value_list(); -} + // return module if asked for + if (args.length() == 0 && nargout == 1) { + retval = octave_value(module_ns->as_value()); + } + + // if call with not output arguments, load globally + else if (args.length() == 0 && nargout == 0) { + + octave_function *me = octave_call_stack::current(); + + octave_swig_type::swig_member_const_iterator mb; + for (mb = module_ns->swig_members_begin(); mb != module_ns->swig_members_end(); ++mb) { + if (mb->second.first && mb->second.first->method) { + SWIG_Octave_InstallFunction(me, mb->first); + } + else if (mb->second.second.is_defined()) { + SWIG_Octave_SetGlobalValue(mb->first, mb->second.second); + SWIG_Octave_LinkGlobalValue(mb->first); + } + } + + SWIG_Octave_SetGlobalValue(SWIG_name_d, module_ns->as_value()); + SWIG_Octave_LinkGlobalValue(SWIG_name_d); + + } + + // otherwise print usage + else { + print_usage(); + } + + return retval; -// workaround bug in octave where installing global variable of custom type and then -// exiting without explicitly clearing the variable causes octave to segfault. -#if OCTAVE_API_VERSION_NUMBER>=37 -octave_value_list SWIG_atexit_func(const octave_value_list &args, int nargout) { - string_vector vars = symbol_table::global_variable_names(); - for (int i = 0; i < vars.length(); i++) - symbol_table::clear_global(vars[i]); - symbol_table::clear_functions(); - return octave_value(); } -#endif %} - diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index aa28dc54c..1b8156b33 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -15,16 +15,13 @@ char cvsroot_octave_cxx[] = "$Id$"; #include "swigmod.h" -static bool global_load = true; static String *global_name = 0; static String *op_prefix = 0; static const char *usage = (char *) "\ Octave Options (available with -octave)\n\ - -global - Load all symbols into the global namespace [default]\n\ -globals - Set used to access C global variables [default: 'cvar']\n\ - - Use '.' to load C global variables into module namespace\n\ - -noglobal - Do not load all symbols into the global namespace\n\ + Use '.' to load C global variables into module namespace\n\ -opprefix - Prefix for global operator functions [default: 'op_']\n\ \n"; @@ -83,12 +80,13 @@ public: if (argv[i]) { if (strcmp(argv[i], "-help") == 0) { fputs(usage, stdout); - } else if (strcmp(argv[i], "-global") == 0) { - global_load = true; - Swig_mark_arg(i); - } else if (strcmp(argv[i], "-noglobal") == 0) { - global_load = false; - Swig_mark_arg(i); + } else if (strcmp(argv[i], "-global") == 0 || + strcmp(argv[i], "-noglobal") == 0) { + Printv(stderr, + "*** -global/-noglobal are no longer supported\n" + "*** global load behaviour is now determined at module load\n" + "*** see the Perl section in the manual for details.\n", NIL); + SWIG_exit(EXIT_FAILURE); } else if (strcmp(argv[i], "-globals") == 0) { if (argv[i + 1]) { global_name = NewString(argv[i + 1]); @@ -179,10 +177,8 @@ public: Printf(f_runtime, "#define SWIG_name %s\n", module); Printf(f_runtime, "\n"); - Printf(f_runtime, "#define SWIG_global_load %s\n", global_load ? "true" : "false"); Printf(f_runtime, "#define SWIG_global_name \"%s\"\n", global_name); Printf(f_runtime, "#define SWIG_op_prefix \"%s\"\n", op_prefix); - Printf(f_runtime, "#define SWIG_atexit_func swig_atexit_%s\n", module); if (directorsEnabled()) { Printf(f_runtime, "#define SWIG_DIRECTORS\n"); @@ -383,7 +379,7 @@ public: virtual int importDirective(Node *n) { String *modname = Getattr(n, "module"); if (modname) - Printf(f_init, "feval(\"%s\",octave_value_list(),0);\n", modname); + Printf(f_init, "feval(\"%s\",octave_value_list(),1);\n", modname); return Language::importDirective(n); }