From e0d85fc939e0c3ea43f645bde0589f4249fd484a Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Thu, 30 Apr 2020 23:40:12 +1000 Subject: [PATCH 01/15] configure.ac: fix calls to mkoctfile for Octave configuration - As of Octave 5.1.0, mkoctfile no longer works with 'env -' (no environment), so need to pass at least PATH and LD_LIBRARY_PATH for it to work. - Still need to clear environment so that it doesn't override mkoctfile defined variables, e.g. CXXFLAGS. --- configure.ac | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index fce5b9ee5..91c74b8ec 100644 --- a/configure.ac +++ b/configure.ac @@ -1079,6 +1079,7 @@ if test -n "$OCTAVE"; then fi AC_MSG_RESULT([${mkoctfile}]) AC_MSG_CHECKING([if ${mkoctfile} works]) + mkoctfile="env - PATH=$PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH ${mkoctfile}" AS_IF([test "x`${mkoctfile} --version 2>/dev/null | sed -n -e '1p' | sed -n -e '/mkoctfile, version/p'`" != x],[ AC_MSG_RESULT([yes]) ],[ @@ -1093,7 +1094,7 @@ if test -n "$OCTAVE"; then AC_MSG_CHECKING([for Octave preprocessor flags]) OCTAVE_CPPFLAGS= for var in CPPFLAGS INCFLAGS ALL_CXXFLAGS; do - for flag in `env - ${mkoctfile} -p ${var}`; do + for flag in `${mkoctfile} -p ${var}`; do case ${flag} in -D*|-I*) OCTAVE_CPPFLAGS="${OCTAVE_CPPFLAGS} ${flag}";; *) ;; @@ -1105,7 +1106,7 @@ if test -n "$OCTAVE"; then AC_MSG_CHECKING([for Octave compiler flags]) OCTAVE_CXXFLAGS= for var in CXX ALL_CXXFLAGS; do - for flag in `env - ${mkoctfile} -p ${var}`; do + for flag in `${mkoctfile} -p ${var}`; do case ${flag} in -std=*|-g*|-W*) OCTAVE_CXXFLAGS="${OCTAVE_CXXFLAGS} ${flag}";; *) ;; @@ -1125,10 +1126,10 @@ if test -n "$OCTAVE"; then AC_MSG_CHECKING([for Octave linker flags]) OCTAVE_LDFLAGS= for var in OCTLIBDIR; do - OCTAVE_LDFLAGS="${OCTAVE_LDFLAGS} "-L`env - ${mkoctfile} -p ${var}` + OCTAVE_LDFLAGS="${OCTAVE_LDFLAGS} "-L`${mkoctfile} -p ${var}` done for var in RDYNAMIC_FLAG RLD_FLAG OCTAVE_LIBS LIBS; do - OCTAVE_LDFLAGS="${OCTAVE_LDFLAGS} "`env - ${mkoctfile} -p ${var}` + OCTAVE_LDFLAGS="${OCTAVE_LDFLAGS} "`${mkoctfile} -p ${var}` done AC_MSG_RESULT([$OCTAVE_LDFLAGS]) From 30132bf77730addafb6150ecd751b855c05394f3 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Fri, 1 May 2020 21:29:41 +1000 Subject: [PATCH 02/15] octrun.swg: remove octave_value type-id from octave_swig_bound_func - The {DECLARE|DEFINE}_OV_TYPEID_FUNCTIONS_AND_DATA declarations attached to this class cause a seg-fault in the module_load Octave example. Removing these declarations fixes the seg-fault. - While cause of seg-fault is unknown, note that (in Octave 5.1.0) the declaration of octave_function, which is the base class for octave_swig_bound_func, does not use these declarations. So it's possible they simply are not required for this type of subclass. --- Lib/octave/octrun.swg | 4 ---- Lib/octave/octruntime.swg | 7 ------- 2 files changed, 11 deletions(-) diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg index 325a4cca3..162772d98 100644 --- a/Lib/octave/octrun.swg +++ b/Lib/octave/octrun.swg @@ -203,11 +203,7 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); std::set dispatch_classes; - private: - - DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA }; - DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_swig_bound_func, "octave_swig_bound_func", "octave_swig_bound_func"); #else #define SWIG_OCTAVE_BOUND_FUNC(func, args) octave_value(func) #endif diff --git a/Lib/octave/octruntime.swg b/Lib/octave/octruntime.swg index f98bf4fe4..6e07aaa70 100644 --- a/Lib/octave/octruntime.swg +++ b/Lib/octave/octruntime.swg @@ -376,7 +376,6 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) { string_vector types = typeinfo.installed_type_names(); bool register_octave_swig_ref = true; bool register_octave_swig_packed = true; - bool register_octave_swig_bound_func = true; for (int i = 0; i < types.numel(); ++i) { if (types(i) == octave_swig_ref::static_type_name()) { register_octave_swig_ref = false; @@ -384,9 +383,6 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) { if (types(i) == octave_swig_packed::static_type_name()) { register_octave_swig_packed = false; } - if (types(i) == octave_swig_bound_func::static_type_name()) { - register_octave_swig_bound_func = false; - } } if (register_octave_swig_ref) { octave_swig_ref::register_type(); @@ -394,9 +390,6 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) { if (register_octave_swig_packed) { octave_swig_packed::register_type(); } - if (register_octave_swig_bound_func) { - octave_swig_bound_func::register_type(); - } } #else octave_swig_ref::register_type(); From 26423d06b3934b5e584beeca62b56e4a861e45a2 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Fri, 1 May 2020 21:19:53 +1000 Subject: [PATCH 03/15] octruntime.swg: do not use atexit() to quit Octave - This reverts commit 931656bcbe7c2bf37bb5d831b47fab9a38695e91 - Since atexit() does not pass along the desired exit status, __swig_atexit__() always exits with status zero, regardless of whether Octave completed successfully or raised an error. - This means the success/failure of Octave scripts which load SWIG modules cannot be determined by other programs, which makes them unusable. - Instead, provide a Octave function swig_exit() which calls ::_Exit() with a given exit status. This way at least a clean exit from Octave can be guaranteed for future versions if the seg-fault problem is not fixed. --- Lib/octave/octruntime.swg | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/Lib/octave/octruntime.swg b/Lib/octave/octruntime.swg index 6e07aaa70..2f0cf58aa 100644 --- a/Lib/octave/octruntime.swg +++ b/Lib/octave/octruntime.swg @@ -315,13 +315,29 @@ DEFUN_DLD( swig_octave_prereq, args, nargout, swig_octave_prereq_usage ) { return octave_value(prereq); } +static const char *const swig_exit_usage = "-*- texinfo -*- \n\ +@deftypefn {Loadable Function} {} swig_exit([@var{exit_status}])\n\ +Exit Octave without performing any memory cleanup.\n\ +@end deftypefn"; + +DEFUN_DLD( swig_exit, args, nargout, swig_exit_usage ) { + if (args.length() > 1) { + error("swig_exit: must be called with at most one arguments"); + return octave_value_list(); + } + int exit_status = 0; + if (args.length() == 1) { + exit_status = args(0).int_value(); + } + ::_Exit(exit_status); + return octave_value(); +} + static const char *const SWIG_name_usage = "-*- texinfo -*- \n\ @deftypefn {Loadable Module} {} " SWIG_name_d "\n\ Loads the SWIG-generated module `" SWIG_name_d "'.\n\ @end deftypefn"; -void __swig_atexit__(void) { ::_Exit(0); } - DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) { static octave_swig_type* module_ns = 0; @@ -329,14 +345,15 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) { // workaround to prevent octave seg-faulting on exit: set Octave exit function // octave_exit to _Exit, which exits immediately without trying to cleanup memory. // definitely affected version 3.2.*, not sure about 3.3.*, seems to be fixed in - // version 3.4.*, but reappeared in 4.2.*, so turn on for all versions after 3.2.*. + // version 3.4.*, reappeared in 4.2.*, hack not possible in 4.4.* or later due to + // removal of octave_exit, so turn on for all versions between 3.2.*. and 4.4.*. // can be turned off with macro definition. #ifndef SWIG_OCTAVE_NO_SEGFAULT_HACK -#if SWIG_OCTAVE_PREREQ(4,4,0) - atexit(__swig_atexit__); -#elif SWIG_OCTAVE_PREREQ(3,2,0) +#if !SWIG_OCTAVE_PREREQ(4,4,0) +#if SWIG_OCTAVE_PREREQ(3,2,0) octave_exit = ::_Exit; #endif +#endif #endif // check for no input and output args @@ -420,6 +437,9 @@ DEFUN_DLD( SWIG_name, args, nargout, SWIG_name_usage ) { if (!SWIG_Octave_InstallFunction(me, "swig_octave_prereq")) { return octave_value_list(); } + if (!SWIG_Octave_InstallFunction(me, "swig_exit")) { + return octave_value_list(); + } octave_swig_type* cvar_ns=0; if (std::string(SWIG_global_name) != ".") { From 66f4f7de8e5a80d48d6b63b47f6fa75a779da35d Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Thu, 30 Apr 2020 23:45:39 +1000 Subject: [PATCH 04/15] octave.cxx: replace Printf() with Append() for consistency --- Source/Modules/octave.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index 1297d2445..4a4e4c956 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -846,7 +846,7 @@ public: Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); } Append(setf->code, "fail:\n"); - Printf(setf->code, "return octave_value_list();\n"); + Append(setf->code, "return octave_value_list();\n"); } else { Printf(setf->code, "return octave_set_immutable(args,nargout);"); } From 99bb5dcc70e504d4671a007e5582c72e09d6d77f Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Thu, 30 Apr 2020 23:47:29 +1000 Subject: [PATCH 05/15] octave.cxx: remote whitespaces --- Source/Modules/octave.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index 4a4e4c956..ca57d3686 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -866,10 +866,10 @@ public: } else { Swig_warning(WARN_TYPEMAP_VAROUT_UNDEF, input_file, line_number, "Unable to read variable of type %s\n", SwigType_str(t, 0)); } - Append(getf->code, " return obj;\n"); + Append(getf->code, "return obj;\n"); if (addfail) { Append(getf->code, "fail:\n"); - Append(getf->code, " return octave_value_list();\n"); + Append(getf->code, "return octave_value_list();\n"); } Append(getf->code, "}\n"); Wrapper_print(getf, f_wrappers); From f6286a1b19cff2144a1803d39374390f6008bc7f Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Thu, 30 Apr 2020 23:48:36 +1000 Subject: [PATCH 06/15] octave.cxx: this belongs in the code (as opposed to definition) section --- Source/Modules/octave.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index ca57d3686..8c3928285 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -830,7 +830,7 @@ public: String *setwname = Swig_name_wrapper(setname); Octave_begin_function(n, setf->def, setname, setwname, true); - Printf(setf->def, "if (!SWIG_check_num_args(\"%s_set\",args.length(),1,1,0)) return octave_value_list();", iname); + Printf(setf->code, "if (!SWIG_check_num_args(\"%s_set\",args.length(),1,1,0)) return octave_value_list();", iname); if (is_assignable(n)) { Setattr(n, "wrap:name", setname); if ((tm = Swig_typemap_lookup("varin", n, name, 0))) { From e67f12558206c0d69d3cfb297248a49e6d5add4c Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Thu, 30 Apr 2020 23:50:02 +1000 Subject: [PATCH 07/15] octave.cxx: add missing return statement before "fail:" label --- Source/Modules/octave.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index 8c3928285..5c9bd45d5 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -845,6 +845,7 @@ public: } else { Swig_warning(WARN_TYPEMAP_VARIN_UNDEF, input_file, line_number, "Unable to set variable of type %s.\n", SwigType_str(t, 0)); } + Append(setf->code, "return octave_value_list();\n"); Append(setf->code, "fail:\n"); Append(setf->code, "return octave_value_list();\n"); } else { From d9c94848ec2e6fd1187fd3e11a6eda0aeb20fa85 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Sat, 2 May 2020 03:35:05 +1000 Subject: [PATCH 08/15] octave.cxx: fix exception raising for newer Octave versions - Since (at least) Octave 5.1.0, the Octave error() function now raises a C++ exception, which if uncaught immediately exits a SWIG wrapper function, bypassing any cleanup code that may appear after a "fail:" label. - This patch adds a "try { ... } catch(...) { }" block around the contents of SWIG wrapper functions to first execute the cleanup code before rethrowing any exception raised. - It is backward compatible with earlier versions of Octave where error() does not raise an exception, which will still branch to the "fail:" block to execute cleanup code if an error is encountered. --- CHANGES.current | 16 ++++++++++++++++ Source/Modules/octave.cxx | 17 ++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CHANGES.current b/CHANGES.current index b45fee280..3bded39e3 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -16,6 +16,22 @@ Version 4.0.2 (in progress) 2020-05-24: vapier [JS] #1796 Fix pkg-config invocation in configure. +2020-04-30: kwwette + [Octave] Fix exception raising for newer Octave versions + Since (at least) Octave 5.1.0, the Octave error() function now raises a C++ exception, + which if uncaught immediately exits a SWIG wrapper function, bypassing any cleanup code + that may appear after a "fail:" label. This patch adds a "try { ... } catch(...) { }" + block around the contents of SWIG wrapper functions to first execute the cleanup code + before rethrowing any exception raised. It is backward compatible with earlier versions + of Octave where error() does not raise an exception, which will still branch to the + "fail:" block to execute cleanup code if an error is encountered. + + Note that the new "try { ... } catch(...) { }" block will localise any local variables + used in typemaps that were NOT declared through SWIG's %typemap(...) syntax, so it's + possible this could break existing SWIG wrappers which were implicitly sharing local + variables between typemaps. This can be fixed, however, by declaring local variables + which need to be shared between typemaps through SWIG's %typemap(...) syntax. + 2020-02-18: ryannevell [Lua] #1728 Add support for LUA lightuserdata to SWIG_Lua_ConvertPtr. diff --git a/Source/Modules/octave.cxx b/Source/Modules/octave.cxx index 5c9bd45d5..b1769e42a 100644 --- a/Source/Modules/octave.cxx +++ b/Source/Modules/octave.cxx @@ -567,6 +567,10 @@ public: Wrapper *f = NewWrapper(); Octave_begin_function(n, f->def, iname, overname, !overloaded); + // Start default try block to execute + // cleanup code if exception is thrown + Printf(f->code, "try {\n"); + emit_parameter_variables(l, f); emit_attach_parmmaps(l, f); Setattr(n, "wrap:parms", l); @@ -754,9 +758,20 @@ public: } Printf(f->code, "return _out;\n"); - Printf(f->code, "fail:\n"); // we should free locals etc if this happens + + // Execute cleanup code if branched to fail: label + Printf(f->code, "fail:\n"); Printv(f->code, cleanup, NIL); Printf(f->code, "return octave_value_list();\n"); + + // Execute cleanup code if exception was thrown + Printf(f->code, "}\n"); + Printf(f->code, "catch(...) {\n"); + Printv(f->code, cleanup, NIL); + Printf(f->code, "throw;\n"); + Printf(f->code, "}\n"); + + // End wrapper function Printf(f->code, "}\n"); /* Substitute the cleanup code */ From d8d0466e8d18d3845343986cb52b47ac77515f70 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Fri, 29 May 2020 19:19:35 +1000 Subject: [PATCH 09/15] Tools/travis-osx-install.sh: use Tools/brew-install to install Octave --- Tools/travis-osx-install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/travis-osx-install.sh b/Tools/travis-osx-install.sh index 393d96e60..99580384c 100755 --- a/Tools/travis-osx-install.sh +++ b/Tools/travis-osx-install.sh @@ -23,7 +23,7 @@ case "$SWIGLANG" in travis_retry brew install lua ;; "octave") - travis_retry brew install octave + travis_retry Tools/brew-install octave ;; "python") WITHLANG=$SWIGLANG$PY3 From df8bb1feeb200caf718b53168c056ad0e61bb8ab Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Sun, 31 May 2020 01:52:42 +1000 Subject: [PATCH 10/15] Tools/travis-osx-install.sh: disable 'brew cleanup' to save Travis job run time --- Tools/travis-osx-install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tools/travis-osx-install.sh b/Tools/travis-osx-install.sh index 99580384c..71d2b2dd0 100755 --- a/Tools/travis-osx-install.sh +++ b/Tools/travis-osx-install.sh @@ -4,6 +4,9 @@ set -e # exit on failure (same as -o errexit) +# Disable 'brew cleanup', just wastes Travis job run time +export HOMEBREW_NO_INSTALL_CLEANUP=1 + sw_vers travis_retry brew update travis_retry brew list From d11e29615d43a5962129724b4097422282ebd8fa Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Fri, 29 May 2020 17:05:01 +1000 Subject: [PATCH 11/15] Octave: use pre-compiled headers to speed up test suite, if supported --- .gitignore | 2 + Examples/Makefile.in | 33 ++++++- Examples/octave/example.mk | 12 +-- Examples/test-suite/octave/Makefile.in | 18 ++++ Lib/octave/director.swg | 2 - Lib/octave/extra-install.list | 2 + Lib/octave/octcontainer.swg | 7 -- Lib/octave/octheaders.hpp | 130 +++++++++++++++++++++++++ Lib/octave/octrun.swg | 4 - Lib/octave/octruntime.swg | 111 +-------------------- Lib/octave/std_complex.i | 4 - configure.ac | 33 +++++++ 12 files changed, 225 insertions(+), 133 deletions(-) create mode 100644 Lib/octave/extra-install.list create mode 100644 Lib/octave/octheaders.hpp diff --git a/.gitignore b/.gitignore index 1f1561475..5df510547 100644 --- a/.gitignore +++ b/.gitignore @@ -173,6 +173,8 @@ Examples/ocaml/**/swigp4.ml # Octave swigexample*.oct Examples/test-suite/octave/*.oct +Examples/test-suite/octave/octheaders.hpp +Examples/test-suite/octave/octheaders.hpp.gch # Perl5 Examples/test-suite/perl5/*.pm diff --git a/Examples/Makefile.in b/Examples/Makefile.in index 6fbca29db..87386f7eb 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -58,6 +58,7 @@ INTERFACE = INTERFACEDIR = INTERFACEPATH = $(SRCDIR)$(INTERFACEDIR)$(INTERFACE) SWIGOPT = +PCHSUPPORT = @PCHSUPPORT@ # SWIG_LIB_DIR and SWIGEXE must be explicitly set by Makefiles using this Makefile SWIG_LIB_DIR = ./Lib @@ -438,14 +439,37 @@ OCTAVE_SO = @OCTAVE_SO@ OCTAVE_SCRIPT = $(SRCDIR)$(RUNME).m +# ---------------------------------------------------------------- +# Pre-compile Octave headers, if supported +# ---------------------------------------------------------------- + +ifeq (yes,$(PCHSUPPORT)) + +octave_precompile_headers: + echo "precompiling $(OCTHEADERS)" + cp -f $(OCTHEADERSSRC) $(OCTHEADERS) + if $(CXX) -c $(CCSHARED) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) $(OCTAVE_CXX) $(OCTHEADERS); then \ + : ; \ + else \ + rm -f $(OCTHEADERSGCH); \ + exit 1; \ + fi + +else + +octave_precompile_headers: + echo "precompiling Octave headers not supported"; exit 1 + +endif + # ---------------------------------------------------------------- # Build a C dynamically loadable module # Note: Octave requires C++ compiler when compiling C wrappers # ---------------------------------------------------------------- octave: $(SRCDIR_SRCS) - $(SWIG) -octave $(SWIGOPT) -o $(ICXXSRCS) $(INTERFACEPATH) - $(CXX) -g -c $(CCSHARED) $(CPPFLAGS) $(CXXFLAGS) $(ICXXSRCS) $(INCLUDES) $(OCTAVE_CXX) + $(SWIG) -octave $(SWIGOCTHDROPT) $(SWIGOPT) -o $(ICXXSRCS) $(INTERFACEPATH) + $(CXX) -g -c $(IOCTHEADERS) $(CCSHARED) $(CPPFLAGS) $(CXXFLAGS) $(ICXXSRCS) $(INCLUDES) $(OCTAVE_CXX) $(CC) -g -c $(CCSHARED) $(CPPFLAGS) $(CFLAGS) $(SRCDIR_SRCS) $(SRCDIR_CSRCS) $(INCLUDES) $(LDSHARED) $(CFLAGS) $(LDFLAGS) $(OBJS) $(IOBJS) $(OCTAVE_DLNK) $(LIBS) -o $(LIBPREFIX)$(TARGET)$(OCTAVE_SO) @@ -454,8 +478,8 @@ octave: $(SRCDIR_SRCS) # ----------------------------------------------------------------- octave_cpp: $(SRCDIR_SRCS) - $(SWIG) -c++ -octave $(SWIGOPT) -o $(ICXXSRCS) $(INTERFACEPATH) - $(CXX) -g -c $(CCSHARED) $(CPPFLAGS) $(CXXFLAGS) $(ICXXSRCS) $(SRCDIR_SRCS) $(SRCDIR_CXXSRCS) $(INCLUDES) $(OCTAVE_CXX) + $(SWIG) -c++ -octave $(SWIGOCTHDROPT) $(SWIGOPT) -o $(ICXXSRCS) $(INTERFACEPATH) + $(CXX) -g -c $(IOCTHEADERS) $(CCSHARED) $(CPPFLAGS) $(CXXFLAGS) $(ICXXSRCS) $(SRCDIR_SRCS) $(SRCDIR_CXXSRCS) $(INCLUDES) $(OCTAVE_CXX) $(CXXSHARED) -g $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(IOBJS) $(OCTAVE_DLNK) $(LIBS) $(CPP_DLLIBS) -o $(LIBPREFIX)$(TARGET)$(OCTAVE_SO) # ----------------------------------------------------------------- @@ -481,6 +505,7 @@ octave_clean: rm -f *_wrap* *~ .~* myoctave@EXEEXT@ *.pyc rm -f core @EXTRA_CLEAN@ rm -f *.@OBJEXT@ *@SO@ *$(OCTAVE_SO) + rm -f $(OCTHEADERS) $(OCTHEADERSGCH) ################################################################## ##### GUILE ###### diff --git a/Examples/octave/example.mk b/Examples/octave/example.mk index 1ab96f038..88608a12b 100644 --- a/Examples/octave/example.mk +++ b/Examples/octave/example.mk @@ -8,25 +8,25 @@ TARGET = swigexample INTERFACE = example.i check: build - $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' octave_run + $(MAKE) -f $(TOP)/Makefile PCHSUPPORT=no SRCDIR='$(SRCDIR)' octave_run build: ifneq (,$(SRCS)) - $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' SRCS='$(SRCS)' \ + $(MAKE) -f $(TOP)/Makefile PCHSUPPORT=no SRCDIR='$(SRCDIR)' SRCS='$(SRCS)' \ SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \ SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' octave else - $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' \ + $(MAKE) -f $(TOP)/Makefile PCHSUPPORT=no SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' \ SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \ SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' octave_cpp endif ifneq (,$(TARGET2)$(SWIGOPT2)) ifneq (,$(SRCS)) - $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' SRCS='$(SRCS)' \ + $(MAKE) -f $(TOP)/Makefile PCHSUPPORT=no SRCDIR='$(SRCDIR)' SRCS='$(SRCS)' \ SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \ SWIGOPT='$(SWIGOPT2)' TARGET='$(TARGET2)' INTERFACE='$(INTERFACE)' octave else - $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' \ + $(MAKE) -f $(TOP)/Makefile PCHSUPPORT=no SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' \ SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \ SWIGOPT='$(SWIGOPT2)' TARGET='$(TARGET2)' INTERFACE='$(INTERFACE)' octave_cpp endif @@ -34,4 +34,4 @@ endif clean: - $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' octave_clean + $(MAKE) -f $(TOP)/Makefile PCHSUPPORT=no SRCDIR='$(SRCDIR)' octave_clean diff --git a/Examples/test-suite/octave/Makefile.in b/Examples/test-suite/octave/Makefile.in index 3c8f3b165..1d54a47bb 100644 --- a/Examples/test-suite/octave/Makefile.in +++ b/Examples/test-suite/octave/Makefile.in @@ -5,6 +5,7 @@ LANGUAGE = octave OCTAVE = @OCTAVE@ SCRIPTSUFFIX = _runme.m +PCHSUPPORT = @PCHSUPPORT@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -61,6 +62,23 @@ CSRCS = octave_empty.c +$(swig_and_compile_multi_cpp) $(run_testcase) +# Pre-compile Octave headers, if supported + +ifeq (yes,$(PCHSUPPORT)) + +export OCTHEADERSSRC = @top_srcdir@/Lib/octave/octheaders.hpp +export OCTHEADERS = @top_builddir@/Examples/test-suite/octave/octheaders.hpp +export OCTHEADERSGCH = $(OCTHEADERS).gch +export SWIGOCTHDROPT = -DSWIG_OCTAVE_EXTERNAL_OCTHEADERS +export IOCTHEADERS = -I@top_builddir@/Examples/test-suite/octave @PCHINCLUDEARG@ $(OCTHEADERS)@PCHINCLUDEEXT@ + +$(OCTHEADERSGCH): $(OCTHEADERSSRC) + $(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile octave_precompile_headers + +$(NOT_BROKEN_TEST_CASES) $(BROKEN_TEST_CASES): $(OCTHEADERSGCH) + +endif + # Runs the testcase. A testcase is only run if # a file is found which has _runme.m appended after the testcase name. run_testcase = \ diff --git a/Lib/octave/director.swg b/Lib/octave/director.swg index bf71d18e8..5b9cd86e0 100644 --- a/Lib/octave/director.swg +++ b/Lib/octave/director.swg @@ -7,8 +7,6 @@ # define SWIG_DIRECTOR_CAST(ARG) dynamic_cast(ARG) -#include - namespace Swig { class Director { diff --git a/Lib/octave/extra-install.list b/Lib/octave/extra-install.list new file mode 100644 index 000000000..41ef94778 --- /dev/null +++ b/Lib/octave/extra-install.list @@ -0,0 +1,2 @@ +# see top-level Makefile.in +octheaders.hpp diff --git a/Lib/octave/octcontainer.swg b/Lib/octave/octcontainer.swg index 310a849d9..80d593f4f 100644 --- a/Lib/octave/octcontainer.swg +++ b/Lib/octave/octcontainer.swg @@ -11,12 +11,6 @@ * be the case. * ----------------------------------------------------------------------------- */ -%{ -#include -#include -%} - - #if !defined(SWIG_NO_EXPORT_ITERATOR_METHODS) # if !defined(SWIG_EXPORT_ITERATOR_METHODS) # define SWIG_EXPORT_ITERATOR_METHODS SWIG_EXPORT_ITERATOR_METHODS @@ -64,7 +58,6 @@ namespace swig { %fragment("OctSequence_Base","header",fragment="") { -%#include namespace std { template <> diff --git a/Lib/octave/octheaders.hpp b/Lib/octave/octheaders.hpp new file mode 100644 index 000000000..abf6428e7 --- /dev/null +++ b/Lib/octave/octheaders.hpp @@ -0,0 +1,130 @@ +// +// This header includes all C++ headers required for generated Octave wrapper code. +// Using a single header file allows pre-compilation of Octave headers, as follows: +// * Check out this header file: +// swig -octave -co octheaders.hpp +// * Pre-compile header file into octheaders.hpp.gch: +// g++ -c ... octheaders.hpp +// * Use pre-compiled header file: +// g++ -c -include octheaders.hpp ... +// + +#if !defined(_SWIG_OCTAVE_OCTHEADERS_HPP) +#define _SWIG_OCTAVE_OCTHEADERS_HPP + +// Required C++ headers +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Minimal headers to define Octave version +#include +#include + +// Macro for enabling features which require Octave version >= major.minor.patch +// - Use (OCTAVE_PATCH_VERSION + 0) to handle both '' (released) and '+' (in development) patch numbers +#define SWIG_OCTAVE_PREREQ(major, minor, patch) \ + ( (OCTAVE_MAJOR_VERSION<<16) + (OCTAVE_MINOR_VERSION<<8) + (OCTAVE_PATCH_VERSION + 0) >= ((major)<<16) + ((minor)<<8) + (patch) ) + +// Reconstruct Octave major, minor, and patch versions for releases prior to 3.8.1 +#if !defined(OCTAVE_MAJOR_VERSION) + +# if !defined(OCTAVE_API_VERSION_NUMBER) + +// Hack to distinguish between Octave 3.8.0, which removed OCTAVE_API_VERSION_NUMBER but did not yet +// introduce OCTAVE_MAJOR_VERSION, and Octave <= 3.2, which did not define OCTAVE_API_VERSION_NUMBER +# include +# if defined(octave_ov_h) +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 8 +# define OCTAVE_PATCH_VERSION 0 +# else + +// Hack to distinguish between Octave 3.2 and earlier versions, before OCTAVE_API_VERSION_NUMBER existed +# define ComplexLU __ignore +# include +# undef ComplexLU +# if defined(octave_Complex_LU_h) + +// We know only that this version is prior to Octave 3.2, i.e. OCTAVE_API_VERSION_NUMBER < 37 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 1 +# define OCTAVE_PATCH_VERSION 99 + +# else + +// OCTAVE_API_VERSION_NUMBER == 37 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 2 +# define OCTAVE_PATCH_VERSION 0 + +# endif // defined(octave_Complex_LU_h) + +# endif // defined(octave_ov_h) + +// Correlation between Octave API and version numbers extracted from Octave's +// ChangeLogs; version is the *earliest* released Octave with that API number +# elif OCTAVE_API_VERSION_NUMBER >= 48 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 6 +# define OCTAVE_PATCH_VERSION 0 + +# elif OCTAVE_API_VERSION_NUMBER >= 45 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 4 +# define OCTAVE_PATCH_VERSION 1 + +# elif OCTAVE_API_VERSION_NUMBER >= 42 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 3 +# define OCTAVE_PATCH_VERSION 54 + +# elif OCTAVE_API_VERSION_NUMBER >= 41 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 3 +# define OCTAVE_PATCH_VERSION 53 + +# elif OCTAVE_API_VERSION_NUMBER >= 40 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 3 +# define OCTAVE_PATCH_VERSION 52 + +# elif OCTAVE_API_VERSION_NUMBER >= 39 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 3 +# define OCTAVE_PATCH_VERSION 51 + +# else // OCTAVE_API_VERSION_NUMBER == 38 +# define OCTAVE_MAJOR_VERSION 3 +# define OCTAVE_MINOR_VERSION 3 +# define OCTAVE_PATCH_VERSION 50 + +# endif // !defined(OCTAVE_API_VERSION_NUMBER) + +#endif // !defined(OCTAVE_MAJOR_VERSION) + +// Required Octave headers +#include +#include +#include +#include +#include +#include +#include +#if SWIG_OCTAVE_PREREQ(4,2,0) +#include +#else +#include +#endif +#include +#if SWIG_OCTAVE_PREREQ(4,2,0) +#include +#endif + +#endif // !defined(_SWIG_OCTAVE_OCTHEADERS_HPP) diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg index 162772d98..944b72a63 100644 --- a/Lib/octave/octrun.swg +++ b/Lib/octave/octrun.swg @@ -89,10 +89,6 @@ SWIGRUNTIME void SWIG_Octave_SetModule(void *clientdata, swig_module_info *point // Runtime API implementation -#include -#include -#include - typedef octave_value_list(*octave_func) (const octave_value_list &, int); class octave_swig_type; diff --git a/Lib/octave/octruntime.swg b/Lib/octave/octruntime.swg index 2f0cf58aa..a397fb7c1 100644 --- a/Lib/octave/octruntime.swg +++ b/Lib/octave/octruntime.swg @@ -1,111 +1,10 @@ +#ifdef SWIG_OCTAVE_EXTERNAL_OCTHEADERS %insert(runtime) %{ - -#include -#include - -#include -#include - -// Macro for enabling features which require Octave version >= major.minor.patch -// - Use (OCTAVE_PATCH_VERSION + 0) to handle both '' (released) and '+' (in development) patch numbers -#define SWIG_OCTAVE_PREREQ(major, minor, patch) \ - ( (OCTAVE_MAJOR_VERSION<<16) + (OCTAVE_MINOR_VERSION<<8) + (OCTAVE_PATCH_VERSION + 0) >= ((major)<<16) + ((minor)<<8) + (patch) ) - -// Reconstruct Octave major, minor, and patch versions for releases prior to 3.8.1 -#if !defined(OCTAVE_MAJOR_VERSION) - -# if !defined(OCTAVE_API_VERSION_NUMBER) - -// Hack to distinguish between Octave 3.8.0, which removed OCTAVE_API_VERSION_NUMBER but did not yet -// introduce OCTAVE_MAJOR_VERSION, and Octave <= 3.2, which did not define OCTAVE_API_VERSION_NUMBER -# include -# if defined(octave_ov_h) -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 8 -# define OCTAVE_PATCH_VERSION 0 -# else - -// Hack to distinguish between Octave 3.2 and earlier versions, before OCTAVE_API_VERSION_NUMBER existed -# define ComplexLU __ignore -# include -# undef ComplexLU -# if defined(octave_Complex_LU_h) - -// We know only that this version is prior to Octave 3.2, i.e. OCTAVE_API_VERSION_NUMBER < 37 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 1 -# define OCTAVE_PATCH_VERSION 99 - -# else - -// OCTAVE_API_VERSION_NUMBER == 37 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 2 -# define OCTAVE_PATCH_VERSION 0 - -# endif // defined(octave_Complex_LU_h) - -# endif // defined(octave_ov_h) - -// Correlation between Octave API and version numbers extracted from Octave's -// ChangeLogs; version is the *earliest* released Octave with that API number -# elif OCTAVE_API_VERSION_NUMBER >= 48 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 6 -# define OCTAVE_PATCH_VERSION 0 - -# elif OCTAVE_API_VERSION_NUMBER >= 45 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 4 -# define OCTAVE_PATCH_VERSION 1 - -# elif OCTAVE_API_VERSION_NUMBER >= 42 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 3 -# define OCTAVE_PATCH_VERSION 54 - -# elif OCTAVE_API_VERSION_NUMBER >= 41 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 3 -# define OCTAVE_PATCH_VERSION 53 - -# elif OCTAVE_API_VERSION_NUMBER >= 40 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 3 -# define OCTAVE_PATCH_VERSION 52 - -# elif OCTAVE_API_VERSION_NUMBER >= 39 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 3 -# define OCTAVE_PATCH_VERSION 51 - -# else // OCTAVE_API_VERSION_NUMBER == 38 -# define OCTAVE_MAJOR_VERSION 3 -# define OCTAVE_MINOR_VERSION 3 -# define OCTAVE_PATCH_VERSION 50 - -# endif // !defined(OCTAVE_API_VERSION_NUMBER) - -#endif // !defined(OCTAVE_MAJOR_VERSION) - -#include -#include -#include -#include -#include -#include -#include -#if SWIG_OCTAVE_PREREQ(4,2,0) -#include -#else -#include -#endif -#include -#if SWIG_OCTAVE_PREREQ(4,2,0) -#include -#endif - +#include "octheaders.hpp" %} +#else +%insert(runtime) "octheaders.hpp"; +#endif %insert(runtime) "swigrun.swg"; %insert(runtime) "swigerrors.swg"; diff --git a/Lib/octave/std_complex.i b/Lib/octave/std_complex.i index 30c188244..461e2fdfc 100644 --- a/Lib/octave/std_complex.i +++ b/Lib/octave/std_complex.i @@ -4,10 +4,6 @@ %include -%{ -#include -%} - namespace std { %naturalvar complex; template class complex; diff --git a/configure.ac b/configure.ac index 91c74b8ec..336460889 100644 --- a/configure.ac +++ b/configure.ac @@ -333,6 +333,39 @@ case $host in *) ;; esac +# Check for compiler pre-compiled header support +AC_MSG_CHECKING([if compiler supports pre-compiled headers]) +PCHSUPPORT=no +if test "$CLANGXX" = "yes"; then + PCHINCLUDEARG="-include-pch" + PCHINCLUDEEXT=".gch" +else + PCHINCLUDEARG="-include" + PCHINCLUDEEXT="" +fi +AC_LANG_PUSH([C++]) +echo '#include ' > conftest.hpp +echo '#include "conftest.hpp"' > conftest.cpp +$CXX -c conftest.hpp 2>/dev/null +if test $? -eq 0; then + if test -f conftest.hpp.gch; then + $CXX -H -c -I. ${PCHINCLUDEARG} ./conftest.hpp${PCHINCLUDEEXT} -o conftest.o conftest.cpp >conftest.out 2>&1 + if test $? -eq 0; then + if test "$CLANGXX" = "yes"; then + PCHSUPPORT=yes + elif grep -q '^!.*conftest.hpp.gch$' conftest.out; then + PCHSUPPORT=yes + fi + fi + fi +fi +rm -f conftest.hpp conftest.cpp conftest.out +AC_LANG_POP([C++]) +AC_MSG_RESULT([$PCHSUPPORT]) +AC_SUBST(PCHSUPPORT) +AC_SUBST(PCHINCLUDEARG) +AC_SUBST(PCHINCLUDEEXT) + # Set info about shared libraries. AC_SUBST(SO) AC_SUBST(LDSHARED) From f11e25f3f6ac9a81426f7f7bfb015d3e0ce31d08 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Sat, 30 May 2020 18:18:43 +1000 Subject: [PATCH 12/15] .travis.yml: add Octave test on Ubuntu Bionic --- .travis.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cedce513d..e9a0abec3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -146,7 +146,12 @@ matrix: os: linux env: SWIGLANG=octave SWIGJOBS=-j2 sudo: required - dist: xenial + dist: xenial # Octave v4.0.0 + - compiler: gcc + os: linux + env: SWIGLANG=octave SWIGJOBS=-j2 CPP11=1 + sudo: required + dist: bionic # Octave v4.2.2 - compiler: gcc os: linux env: SWIGLANG=perl5 From 77c0fdaa79629362165cd19660186594b541e32b Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Sun, 31 May 2020 10:43:11 +1000 Subject: [PATCH 13/15] .travis.yml: require Octave build on OSX to pass --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9a0abec3..ee6dfe268 100644 --- a/.travis.yml +++ b/.travis.yml @@ -480,10 +480,6 @@ matrix: env: SWIGLANG=php VER=7.2 sudo: required dist: xenial - # Sometimes hits the Travis 50 minute time limit - - compiler: clang - os: osx - env: SWIGLANG=octave SWIGJOBS=-j2 # Experimental languages - compiler: gcc os: linux From cec09a7e6e6b0d27a7639ef76acea5813f7a70fd Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Sun, 31 May 2020 00:34:18 +1000 Subject: [PATCH 14/15] .travis.yml: build Octave on OSX with CPP=11 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ee6dfe268..385e7be42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -442,7 +442,7 @@ matrix: env: SWIGLANG=lua - compiler: clang os: osx - env: SWIGLANG=octave SWIGJOBS=-j2 + env: SWIGLANG=octave SWIGJOBS=-j2 CPP11=1 - compiler: clang os: osx env: SWIGLANG=perl5 From d73ef20475ac77e5f0fe4f641759e4bebcdc2428 Mon Sep 17 00:00:00 2001 From: Karl Wette Date: Sun, 31 May 2020 10:26:15 +1000 Subject: [PATCH 15/15] octrun.swg: ensure type_id() is set correctly --- Lib/octave/octrun.swg | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/octave/octrun.swg b/Lib/octave/octrun.swg index 944b72a63..1069e0e54 100644 --- a/Lib/octave/octrun.swg +++ b/Lib/octave/octrun.swg @@ -1058,7 +1058,13 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); octave_swig_type *ptr; public: octave_swig_ref(octave_swig_type *_ptr = 0) - :ptr(_ptr) { } + :ptr(_ptr) + { + // Ensure type_id() is set correctly + if (t_id == -1) { + t_id = octave_swig_ref::static_type_id(); + } + } ~octave_swig_ref() { if (ptr) ptr->decref(); } @@ -1199,8 +1205,13 @@ SWIGRUNTIME void swig_acquire_ownership_obj(void *vptr, int own); public: octave_swig_packed(swig_type_info *_type = 0, const void *_buf = 0, size_t _buf_len = 0) - : type(_type), buf((const char*)_buf, (const char*)_buf + _buf_len) { - } + : type(_type), buf((const char*)_buf, (const char*)_buf + _buf_len) + { + // Ensure type_id() is set correctly + if (t_id == -1) { + t_id = octave_swig_packed::static_type_id(); + } + } bool copy(swig_type_info *outtype, void *ptr, size_t sz) const { if (outtype && outtype != type)