changeset 33339:abdb846bafe8

Instantiate octave_base_matrix and octave_base_scalar template classes * ov-base-mat-inst.cc: Add new file to explicitly instantiate template class octave_base_matrix with types that need to be exported from liboctinterp. * ov-base-scalar-inst.cc: Add new file to explicitly instantiate template class octave_base_scalar with types that need to be exported from liboctinterp. * ov-base-scalar-int-inst.cc: Add new file to explicitly instantiate template classes octave_base_int_matrix and octave_base_int_scalar with types that need to be exported from liboctinterp. * ov-base-mat.h, ov-base-scalar.h: Use macro for template export. Mark all member functions for export. * ov-bool-mat.cc, ov-bool-mat.h, ov-bool.h, ov-cell.cc, ov-cell.h, ov-ch-mat.cc, ov-ch-mat.h, ov-complex.cc, ov-complex.h, ov-cx-mat.cc, ov-cx-mat.h, ov-float.cc, ov-float.h, ov-float-complex.cc, ov-float-complex.h, ov-flt-cx-mat.cc, ov-flt-cx-mat.h, ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-int16.cc, ov-int32.cc, ov-int64.cc, ov-int8.cc, ov-intx.h, ov-re-mat.cc, ov-re-mat.h, ov-scalar.cc, ov-scalar.h, ov-uint16.cc, ov-uint32.cc, ov-uint64.cc, ov-uint8.cc: Instantiate template classes octave_base_matrix, octave_base_scalar, octave_base_int_matrix, and octave_base_int_scalar only in one compilation unit. Move extern template class declarations to headers. * ov-base-int.cc: Remove includes that are not needed to prevent potentially unpredicted template instantiations. * ov-base-int.h: Add extern template declarations to avoid multiple instantiations of template class in different compilation units. Add export attributes to all member functions of template class. * ov-base-int.h: Use export attributes for template classes that better work cross-platform. * ov-base.h: Add export attributes to undefined functions. * ov-cell.cc: Move octave_base_matrix<cell> specializations to ov-base-mat-inst.cc. * libinterp/octave-value/module.mk: Add new files to build system. See: https://octave.discourse.group/t/5211
author Markus Mützel <markus.muetzel@gmx.de>
date Sun, 21 Jan 2024 19:34:01 +0100
parents 714c6d2e253e
children 8e6e656b6f61
files libinterp/octave-value/module.mk libinterp/octave-value/ov-base-int-inst.cc libinterp/octave-value/ov-base-int.cc libinterp/octave-value/ov-base-int.h libinterp/octave-value/ov-base-mat-inst.cc libinterp/octave-value/ov-base-mat.h libinterp/octave-value/ov-base-scalar-inst.cc libinterp/octave-value/ov-base-scalar.h libinterp/octave-value/ov-base.h libinterp/octave-value/ov-bool-mat.cc libinterp/octave-value/ov-bool-mat.h libinterp/octave-value/ov-bool.cc libinterp/octave-value/ov-bool.h libinterp/octave-value/ov-cell.cc libinterp/octave-value/ov-cell.h libinterp/octave-value/ov-ch-mat.cc libinterp/octave-value/ov-ch-mat.h libinterp/octave-value/ov-complex.cc libinterp/octave-value/ov-complex.h libinterp/octave-value/ov-cx-mat.cc libinterp/octave-value/ov-cx-mat.h libinterp/octave-value/ov-float.cc libinterp/octave-value/ov-float.h libinterp/octave-value/ov-flt-complex.cc libinterp/octave-value/ov-flt-complex.h libinterp/octave-value/ov-flt-cx-mat.cc libinterp/octave-value/ov-flt-cx-mat.h libinterp/octave-value/ov-flt-re-mat.cc libinterp/octave-value/ov-flt-re-mat.h libinterp/octave-value/ov-int16.cc libinterp/octave-value/ov-int32.cc libinterp/octave-value/ov-int64.cc libinterp/octave-value/ov-int8.cc libinterp/octave-value/ov-intx.h libinterp/octave-value/ov-re-mat.cc libinterp/octave-value/ov-re-mat.h libinterp/octave-value/ov-scalar.cc libinterp/octave-value/ov-scalar.h libinterp/octave-value/ov-uint16.cc libinterp/octave-value/ov-uint32.cc libinterp/octave-value/ov-uint64.cc libinterp/octave-value/ov-uint8.cc
diffstat 42 files changed, 555 insertions(+), 517 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/module.mk	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/module.mk	Sun Jan 21 19:34:01 2024 +0100
@@ -97,6 +97,9 @@
   %reldir%/cdef-package.cc \
   %reldir%/cdef-property.cc \
   %reldir%/cdef-utils.cc \
+  %reldir%/ov-base-int-inst.cc \
+  %reldir%/ov-base-mat-inst.cc \
+  %reldir%/ov-base-scalar-inst.cc \
   %reldir%/ov-base.cc \
   %reldir%/ov-bool-mat.cc \
   %reldir%/ov-bool.cc \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-base-int-inst.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -0,0 +1,60 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2024 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "int8NDArray.h"
+#include "int16NDArray.h"
+#include "int32NDArray.h"
+#include "int64NDArray.h"
+#include "uint8NDArray.h"
+#include "uint16NDArray.h"
+#include "uint32NDArray.h"
+#include "uint64NDArray.h"
+
+#include "ov-base-int.cc"
+
+// instantiate template class with types that need to be exported from library
+
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<int8NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<int16NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<int32NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<int64NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<uint8NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<uint16NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<uint32NDArray>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_matrix<uint64NDArray>;
+
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_int8>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_int16>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_int32>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_int64>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_uint8>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_uint16>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_uint32>;
+template class OCTINTERP_CLASS_TEMPLATE_INSTANTIATION_API octave_base_int_scalar<octave_uint64>;
+
--- a/libinterp/octave-value/ov-base-int.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-base-int.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -58,10 +58,6 @@
 #include "oct-stream.h"
 #include "ops.h"
 #include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
-#include "ov-base-scalar.h"
-#include "ov-base-scalar.cc"
 #include "ov-base-int.h"
 #include "ov-int-traits.h"
 #include "pr-output.h"
--- a/libinterp/octave-value/ov-base-int.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-base-int.h	Sun Jan 21 19:34:01 2024 +0100
@@ -44,8 +44,17 @@
 
 // base int matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<int8NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<int16NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<int32NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<int64NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<uint8NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<uint16NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<uint32NDArray>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<uint64NDArray>;
+
 template <typename T>
-class OCTINTERP_API octave_base_int_matrix : public octave_base_matrix<T>
+class OCTINTERP_TEMPLATE_API octave_base_int_matrix : public octave_base_matrix<T>
 {
 public:
 
@@ -63,7 +72,7 @@
 
   OCTINTERP_API octave_base_value * try_narrowing_conversion ();
 
-  bool isreal () const { return true; }
+  OCTINTERP_API bool isreal () const { return true; }
 
   //  void increment () { matrix += 1; }
 
@@ -114,29 +123,39 @@
 
 // base int scalar values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_int8>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_int16>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_int32>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_int64>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_uint8>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_uint16>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_uint32>;
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<octave_uint64>;
+
 template <typename T>
-class OCTINTERP_API octave_base_int_scalar : public octave_base_scalar<T>
+class OCTINTERP_TEMPLATE_API octave_base_int_scalar : public octave_base_scalar<T>
 {
 public:
 
-  octave_base_int_scalar () : octave_base_scalar<T> () { }
+  OCTINTERP_API octave_base_int_scalar () : octave_base_scalar<T> () { }
 
-  octave_base_int_scalar (const T& s) : octave_base_scalar<T> (s) { }
+  OCTINTERP_API octave_base_int_scalar (const T& s) : octave_base_scalar<T> (s) { }
 
-  ~octave_base_int_scalar () = default;
+  OCTINTERP_API ~octave_base_int_scalar () = default;
 
-  octave_base_value * clone () const
+  OCTINTERP_API octave_base_value * clone () const
   { return new octave_base_int_scalar (*this); }
-  octave_base_value * empty_clone () const
+  OCTINTERP_API octave_base_value * empty_clone () const
   { return new octave_base_int_scalar (); }
 
-  octave_base_value * try_narrowing_conversion () { return nullptr; }
-
-  bool is_maybe_function () const { return false; }
+  OCTINTERP_API octave_base_value * try_narrowing_conversion ()
+  { return nullptr; }
 
-  bool isreal () const { return true; }
+  OCTINTERP_API bool is_maybe_function () const { return false; }
 
-  bool is_real_scalar () const { return true; }
+  OCTINTERP_API bool isreal () const { return true; }
+
+  OCTINTERP_API bool is_real_scalar () const { return true; }
 
   //  void increment () { scalar += 1; }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-base-mat-inst.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2024 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "ov-base-mat.cc"
+
+// instantiate template class with types that need to be exported from library
+
+template class OCTINTERP_API octave_base_matrix<boolNDArray>;
+template class OCTINTERP_API octave_base_matrix<charNDArray>;
+template class OCTINTERP_API octave_base_matrix<int8NDArray>;
+template class OCTINTERP_API octave_base_matrix<int16NDArray>;
+template class OCTINTERP_API octave_base_matrix<int32NDArray>;
+template class OCTINTERP_API octave_base_matrix<int64NDArray>;
+template class OCTINTERP_API octave_base_matrix<uint8NDArray>;
+template class OCTINTERP_API octave_base_matrix<uint16NDArray>;
+template class OCTINTERP_API octave_base_matrix<uint32NDArray>;
+template class OCTINTERP_API octave_base_matrix<uint64NDArray>;
+template class OCTINTERP_API octave_base_matrix<ComplexNDArray>;
+template class OCTINTERP_API octave_base_matrix<FloatComplexNDArray>;
+template class OCTINTERP_API octave_base_matrix<FloatNDArray>;
+template class OCTINTERP_API octave_base_matrix<NDArray>;
+
+
+// Cell is able to handle octave_value indexing by itself, so just forward
+// everything.
+
+template <>
+octave_value
+octave_base_matrix<Cell>::do_index_op (const octave_value_list& idx,
+                                       bool resize_ok)
+{
+  return m_matrix.index (idx, resize_ok);
+}
+
+template <>
+void
+octave_base_matrix<Cell>::assign (const octave_value_list& idx, const Cell& rhs)
+{
+  m_matrix.assign (idx, rhs);
+}
+
+template <>
+void
+octave_base_matrix<Cell>::assign (const octave_value_list& idx,
+                                  octave_value rhs)
+{
+  // FIXME: Really?
+  if (rhs.iscell ())
+    m_matrix.assign (idx, rhs.cell_value ());
+  else
+    m_matrix.assign (idx, Cell (rhs));
+}
+
+template <>
+void
+octave_base_matrix<Cell>::delete_elements (const octave_value_list& idx)
+{
+  m_matrix.delete_elements (idx);
+}
+
+// FIXME: this list of specializations is becoming so long that we should
+// really ask whether octave_cell should inherit from octave_base_matrix at all.
+
+template <>
+std::string
+octave_base_matrix<Cell>::edit_display (const float_display_format&,
+                                        octave_idx_type i,
+                                        octave_idx_type j) const
+{
+  octave_value val = m_matrix(i, j);
+
+  std::string tname = val.type_name ();
+  dim_vector dv = val.dims ();
+  std::string dimstr = dv.str ();
+  return "[" + dimstr + " " + tname + "]";
+}
+
+template <>
+octave_value
+octave_base_matrix<Cell>::fast_elem_extract (octave_idx_type n) const
+{
+  if (n < m_matrix.numel ())
+    return Cell (m_matrix(n));
+  else
+    return octave_value ();
+}
+
+template <>
+bool
+octave_base_matrix<Cell>::fast_elem_insert (octave_idx_type n,
+                                            const octave_value& x)
+{
+  const octave_base_matrix<Cell> *xrep
+    = dynamic_cast<const octave_base_matrix<Cell> *> (&x.get_rep ());
+
+  bool retval = xrep && xrep->m_matrix.numel () == 1 && n < m_matrix.numel ();
+  if (retval)
+    m_matrix(n) = xrep->m_matrix(0);
+
+  return retval;
+}
+
+template class OCTINTERP_API octave_base_matrix<Cell>;
--- a/libinterp/octave-value/ov-base-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-base-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -45,16 +45,16 @@
 // Real matrix values.
 
 template <typename MT>
-class OCTINTERP_API octave_base_matrix : public octave_base_value
+class OCTINTERP_TEMPLATE_API octave_base_matrix : public octave_base_value
 {
 public:
 
   typedef MT object_type;
 
-  octave_base_matrix ()
+  OCTINTERP_API octave_base_matrix ()
     : octave_base_value (), m_matrix (), m_typ (), m_idx_cache () { }
 
-  octave_base_matrix (const MT& m, const MatrixType& t = MatrixType ())
+  OCTINTERP_API octave_base_matrix (const MT& m, const MatrixType& t = MatrixType ())
     : octave_base_value (), m_matrix (m),
       m_typ (t.is_known () ? new MatrixType (t) : nullptr), m_idx_cache ()
   {
@@ -62,22 +62,22 @@
       m_matrix.resize (dim_vector (0, 0));
   }
 
-  octave_base_matrix (const octave_base_matrix& m)
+  OCTINTERP_API octave_base_matrix (const octave_base_matrix& m)
     : octave_base_value (), m_matrix (m.m_matrix),
       m_typ (m.m_typ ? new MatrixType (*m.m_typ) : nullptr),
       m_idx_cache (m.m_idx_cache ? new octave::idx_vector (*m.m_idx_cache)
                    : nullptr)
   { }
 
-  ~octave_base_matrix () { clear_cached_info (); }
+  OCTINTERP_API ~octave_base_matrix () { clear_cached_info (); }
 
-  std::size_t byte_size () const { return m_matrix.byte_size (); }
+  OCTINTERP_API std::size_t byte_size () const { return m_matrix.byte_size (); }
 
-  octave_value squeeze () const { return MT (m_matrix.squeeze ()); }
+  OCTINTERP_API octave_value squeeze () const { return MT (m_matrix.squeeze ()); }
 
-  octave_value full_value () const { return m_matrix; }
+  OCTINTERP_API octave_value full_value () const { return m_matrix; }
 
-  void maybe_economize () { m_matrix.maybe_economize (); }
+  OCTINTERP_API void maybe_economize () { m_matrix.maybe_economize (); }
 
   // We don't need to override all three forms of subsref.  The using
   // declaration will avoid warnings about partially-overloaded virtual
@@ -87,11 +87,11 @@
   OCTINTERP_API octave_value
   subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
-  octave_value_list
+  OCTINTERP_API octave_value_list
   simple_subsref (char type, octave_value_list& idx, int nargout);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx, int)
+  OCTINTERP_API octave_value_list
+  subsref (const std::string& type, const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
   OCTINTERP_API octave_value
@@ -115,58 +115,65 @@
 
   OCTINTERP_API void delete_elements (const octave_value_list& idx);
 
-  dim_vector dims () const { return m_matrix.dims (); }
+  OCTINTERP_API dim_vector dims () const { return m_matrix.dims (); }
 
-  octave_idx_type numel () const { return m_matrix.numel (); }
+  OCTINTERP_API octave_idx_type numel () const { return m_matrix.numel (); }
 
-  int ndims () const { return m_matrix.ndims (); }
+  OCTINTERP_API int ndims () const { return m_matrix.ndims (); }
 
-  octave_idx_type nnz () const { return m_matrix.nnz (); }
+  OCTINTERP_API octave_idx_type nnz () const { return m_matrix.nnz (); }
 
-  octave_value reshape (const dim_vector& new_dims) const
+  OCTINTERP_API octave_value reshape (const dim_vector& new_dims) const
   { return MT (m_matrix.reshape (new_dims)); }
 
-  octave_value permute (const Array<int>& vec, bool inv = false) const
+  OCTINTERP_API octave_value permute (const Array<int>& vec, bool inv = false) const
   { return MT (m_matrix.permute (vec, inv)); }
 
-  octave_value resize (const dim_vector& dv, bool fill = false) const;
-
-  octave_value all (int dim = 0) const { return m_matrix.all (dim); }
-  octave_value any (int dim = 0) const { return m_matrix.any (dim); }
+  OCTINTERP_API octave_value
+  resize (const dim_vector& dv, bool fill = false) const;
 
-  MatrixType matrix_type () const { return m_typ ? *m_typ : MatrixType (); }
-  MatrixType matrix_type (const MatrixType& _typ) const;
+  OCTINTERP_API octave_value all (int dim = 0) const
+  { return m_matrix.all (dim); }
+  OCTINTERP_API octave_value any (int dim = 0) const
+  { return m_matrix.any (dim); }
 
-  octave_value diag (octave_idx_type k = 0) const
+  OCTINTERP_API MatrixType matrix_type () const
+  { return m_typ ? *m_typ : MatrixType (); }
+  OCTINTERP_API MatrixType matrix_type (const MatrixType& _typ) const;
+
+  OCTINTERP_API octave_value diag (octave_idx_type k = 0) const
   { return octave_value (m_matrix.diag (k)); }
 
-  octave_value diag (octave_idx_type m, octave_idx_type n) const
+  OCTINTERP_API octave_value diag (octave_idx_type m, octave_idx_type n) const
   { return octave_value (m_matrix.diag (m, n)); }
 
-  octave_value sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const
+  OCTINTERP_API octave_value
+  sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const
   { return octave_value (m_matrix.sort (dim, mode)); }
-  octave_value sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
-                     sortmode mode = ASCENDING) const
+  OCTINTERP_API octave_value
+  sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
+        sortmode mode = ASCENDING) const
   { return octave_value (m_matrix.sort (sidx, dim, mode)); }
 
-  sortmode issorted (sortmode mode = UNSORTED) const
+  OCTINTERP_API sortmode issorted (sortmode mode = UNSORTED) const
   { return m_matrix.issorted (mode); }
 
-  Array<octave_idx_type> sort_rows_idx (sortmode mode = ASCENDING) const
+  OCTINTERP_API Array<octave_idx_type>
+  sort_rows_idx (sortmode mode = ASCENDING) const
   { return m_matrix.sort_rows_idx (mode); }
 
-  sortmode is_sorted_rows (sortmode mode = UNSORTED) const
+  OCTINTERP_API sortmode is_sorted_rows (sortmode mode = UNSORTED) const
   { return m_matrix.is_sorted_rows (mode); }
 
-  bool is_matrix_type () const { return true; }
+  OCTINTERP_API bool is_matrix_type () const { return true; }
 
-  bool is_full_num_matrix () const { return true; }
+  OCTINTERP_API bool is_full_num_matrix () const { return true; }
 
-  bool isnumeric () const { return true; }
+  OCTINTERP_API bool isnumeric () const { return true; }
 
-  bool is_defined () const { return true; }
+  OCTINTERP_API bool is_defined () const { return true; }
 
-  bool is_constant () const { return true; }
+  OCTINTERP_API bool is_constant () const { return true; }
 
   OCTINTERP_API bool is_true () const;
 
@@ -185,13 +192,13 @@
   edit_display (const float_display_format& fmt,
                 octave_idx_type i, octave_idx_type j) const;
 
-  MT& matrix_ref ()
+  OCTINTERP_API MT& matrix_ref ()
   {
     clear_cached_info ();
     return m_matrix;
   }
 
-  const MT& matrix_ref () const
+  OCTINTERP_API const MT& matrix_ref () const
   {
     return m_matrix;
   }
@@ -204,20 +211,21 @@
 
   // This function exists to support the MEX interface.
   // You should not use it anywhere else.
-  const void * mex_get_data () const { return m_matrix.data (); }
+  OCTINTERP_API const void * mex_get_data () const { return m_matrix.data (); }
 
 protected:
 
   MT m_matrix;
 
-  octave::idx_vector set_idx_cache (const octave::idx_vector& idx) const
+  OCTINTERP_API octave::idx_vector
+  set_idx_cache (const octave::idx_vector& idx) const
   {
     delete m_idx_cache;
     m_idx_cache = new octave::idx_vector (idx);
     return idx;
   }
 
-  void clear_cached_info () const
+  OCTINTERP_API void clear_cached_info () const
   {
     delete m_typ; m_typ = nullptr;
     delete m_idx_cache; m_idx_cache = nullptr;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/octave-value/ov-base-scalar-inst.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2024 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Octave is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include "ov-base-scalar.cc"
+
+// instantiate template class with types that need to be exported from library
+
+template class OCTINTERP_API octave_base_scalar<bool>;
+template class OCTINTERP_API octave_base_scalar<double>;
+template class OCTINTERP_API octave_base_scalar<float>;
+template class OCTINTERP_API octave_base_scalar<Complex>;
+template class OCTINTERP_API octave_base_scalar<FloatComplex>;
+template class OCTINTERP_API octave_base_scalar<octave_int8>;
+template class OCTINTERP_API octave_base_scalar<octave_int16>;
+template class OCTINTERP_API octave_base_scalar<octave_int32>;
+template class OCTINTERP_API octave_base_scalar<octave_int64>;
+template class OCTINTERP_API octave_base_scalar<octave_uint8>;
+template class OCTINTERP_API octave_base_scalar<octave_uint16>;
+template class OCTINTERP_API octave_base_scalar<octave_uint32>;
+template class OCTINTERP_API octave_base_scalar<octave_uint64>;
--- a/libinterp/octave-value/ov-base-scalar.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-base-scalar.h	Sun Jan 21 19:34:01 2024 +0100
@@ -50,20 +50,20 @@
 
   typedef ST scalar_type;
 
-  octave_base_scalar ()
+  OCTINTERP_API octave_base_scalar ()
     : octave_base_value (), scalar () { }
 
-  octave_base_scalar (const ST& s)
+  OCTINTERP_API octave_base_scalar (const ST& s)
     : octave_base_value (), scalar (s) { }
 
-  octave_base_scalar (const octave_base_scalar& s)
+  OCTINTERP_API octave_base_scalar (const octave_base_scalar& s)
     : octave_base_value (), scalar (s.scalar) { }
 
-  ~octave_base_scalar () = default;
+  OCTINTERP_API ~octave_base_scalar () = default;
 
-  octave_value squeeze () const { return scalar; }
+  OCTINTERP_API octave_value squeeze () const { return scalar; }
 
-  octave_value full_value () const { return scalar; }
+  OCTINTERP_API octave_value full_value () const { return scalar; }
 
   // We don't need to override all three forms of subsref.  The using
   // declaration will avoid warnings about partially-overloaded virtual
@@ -73,71 +73,74 @@
   OCTINTERP_API octave_value
   subsref (const std::string& type, const std::list<octave_value_list>& idx);
 
-  octave_value_list subsref (const std::string& type,
-                             const std::list<octave_value_list>& idx, int)
+  OCTINTERP_API octave_value_list
+  subsref (const std::string& type, const std::list<octave_value_list>& idx, int)
   { return subsref (type, idx); }
 
   OCTINTERP_API octave_value
   subsasgn (const std::string& type, const std::list<octave_value_list>& idx,
             const octave_value& rhs);
 
-  bool is_constant () const { return true; }
+  OCTINTERP_API bool is_constant () const { return true; }
 
-  bool is_defined () const { return true; }
+  OCTINTERP_API bool is_defined () const { return true; }
 
   OCTINTERP_API dim_vector dims () const;
 
-  octave_idx_type numel () const { return 1; }
+  OCTINTERP_API octave_idx_type numel () const { return 1; }
 
-  int ndims () const { return 2; }
+  OCTINTERP_API int ndims () const { return 2; }
 
-  octave_idx_type nnz () const { return (scalar != ST () ? 1 : 0); }
+  OCTINTERP_API octave_idx_type nnz () const { return (scalar != ST () ? 1 : 0); }
 
   OCTINTERP_API octave_value permute (const Array<int>&, bool = false) const;
 
   OCTINTERP_API octave_value reshape (const dim_vector& new_dims) const;
 
-  std::size_t byte_size () const { return sizeof (ST); }
+  OCTINTERP_API std::size_t byte_size () const { return sizeof (ST); }
 
-  octave_value all (int = 0) const { return (scalar != ST ()); }
+  OCTINTERP_API octave_value all (int = 0) const { return (scalar != ST ()); }
 
-  octave_value any (int = 0) const { return (scalar != ST ()); }
+  OCTINTERP_API octave_value any (int = 0) const { return (scalar != ST ()); }
 
   OCTINTERP_API octave_value diag (octave_idx_type k = 0) const;
 
   OCTINTERP_API octave_value diag (octave_idx_type m, octave_idx_type n) const;
 
-  octave_value sort (octave_idx_type, sortmode) const
+  OCTINTERP_API octave_value sort (octave_idx_type, sortmode) const
   { return octave_value (scalar); }
-  octave_value sort (Array<octave_idx_type>& sidx, octave_idx_type,
-                     sortmode) const
+
+  OCTINTERP_API octave_value
+  sort (Array<octave_idx_type>& sidx, octave_idx_type, sortmode) const
   {
     sidx.resize (dim_vector (1, 1));
     sidx(0) = 0;
     return octave_value (scalar);
   }
 
-  sortmode issorted (sortmode mode = UNSORTED) const
+  OCTINTERP_API sortmode issorted (sortmode mode = UNSORTED) const
   { return mode == UNSORTED ? ASCENDING : mode; }
 
-  Array<octave_idx_type> sort_rows_idx (sortmode) const
+  OCTINTERP_API Array<octave_idx_type> sort_rows_idx (sortmode) const
   {
     return Array<octave_idx_type> (dim_vector (1, 1),
                                    static_cast<octave_idx_type> (0));
   }
 
-  sortmode is_sorted_rows (sortmode mode = UNSORTED) const
+  OCTINTERP_API sortmode is_sorted_rows (sortmode mode = UNSORTED) const
   { return mode == UNSORTED ? ASCENDING : mode; }
 
-  MatrixType matrix_type () const { return MatrixType::Diagonal; }
-  MatrixType matrix_type (const MatrixType&) const
+  OCTINTERP_API MatrixType matrix_type () const
+  { return MatrixType::Diagonal; }
+
+  OCTINTERP_API MatrixType matrix_type (const MatrixType&) const
   { return matrix_type (); }
 
-  bool is_maybe_function () const { return false; }
+  OCTINTERP_API bool is_maybe_function () const { return false; }
 
-  bool is_scalar_type () const { return true; }
+  OCTINTERP_API bool is_scalar_type () const { return true; }
 
-  bool isnumeric () const { return true; }
+  OCTINTERP_API bool isnumeric () const { return true; }
 
   OCTINTERP_API bool is_true () const;
 
@@ -159,11 +162,11 @@
 
   // This function exists to support the MEX interface.
   // You should not use it anywhere else.
-  const void * mex_get_data () const { return &scalar; }
+  OCTINTERP_API const void * mex_get_data () const { return &scalar; }
 
-  const ST& scalar_ref () const { return scalar; }
+  OCTINTERP_API const ST& scalar_ref () const { return scalar; }
 
-  ST& scalar_ref () { return scalar; }
+  OCTINTERP_API ST& scalar_ref () { return scalar; }
 
   OCTINTERP_API octave_value fast_elem_extract (octave_idx_type n) const;
 
--- a/libinterp/octave-value/ov-base.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-base.h	Sun Jan 21 19:34:01 2024 +0100
@@ -192,20 +192,21 @@
     static int static_type_id () { return s_t_id; }                   \
     static std::string static_type_name () { return s_t_name; }       \
     static std::string static_class_name () { return s_c_name; }      \
-    static void register_type ();                                     \
-    static void register_type (octave::type_info&);                   \
+    OCTINTERP_API static void register_type ();                       \
+    OCTINTERP_API static void register_type (octave::type_info&);     \
                                                                       \
   private:                                                            \
-    static int s_t_id;                                                \
-    static const std::string s_t_name;                                \
-    static const std::string s_c_name;
+    static OCTINTERP_API int s_t_id;                                  \
+    static OCTINTERP_API const std::string s_t_name;                  \
+    static OCTINTERP_API const std::string s_c_name;
 
 #define DECLARE_TEMPLATE_OV_TYPEID_SPECIALIZATIONS(cls, type)         \
-  template <> void cls<type>::register_type ();                       \
-  template <> void cls<type>::register_type (octave::type_info&);     \
-  template <> int cls<type>::s_t_id;                                  \
-  template <> const std::string cls<type>::s_t_name;                  \
-  template <> const std::string cls<type>::s_c_name;
+  template <> OCTINTERP_API void cls<type>::register_type ();         \
+  template <> OCTINTERP_API void                                      \
+  OCTINTERP_API cls<type>::register_type (octave::type_info&);        \
+  template <> OCTINTERP_API int cls<type>::s_t_id;                    \
+  template <> OCTINTERP_API const std::string cls<type>::s_t_name;    \
+  template <> OCTINTERP_API const std::string cls<type>::s_c_name;
 
 // FIXME: The 'new' operator below creates an 8-byte memory leak for every
 // registered data type (of which there are 58 built-in to Octave, plus any
@@ -266,7 +267,7 @@
 
   friend class octave_value;
 
-  octave_base_value ();
+  OCTINTERP_API octave_base_value ();
 
   octave_base_value (const octave_base_value&) : octave_base_value () { }
 
@@ -277,7 +278,7 @@
   clone () const { return new octave_base_value (*this); }
 
   // Empty clone.
-  virtual octave_base_value *
+  virtual OCTINTERP_API octave_base_value *
   empty_clone () const;
 
   // Unique clone.  Usually clones, but may be overridden to fake the
@@ -296,76 +297,77 @@
   numeric_demotion_function () const
   { return type_conv_info (); }
 
-  virtual octave_value squeeze () const;
+  virtual OCTINTERP_API octave_value squeeze () const;
 
-  virtual octave_value full_value () const;
+  virtual OCTINTERP_API octave_value full_value () const;
 
   // Will return a copy of it-self when the representation
   // allready is a scalar (.i.e. double). The const variant
   // as_double () would allocate a new octave value.
-  virtual octave_value as_double_or_copy ();
+  virtual OCTINTERP_API octave_value as_double_or_copy ();
 
-  virtual octave_value as_double () const;
-  virtual octave_value as_single () const;
+  virtual OCTINTERP_API octave_value as_double () const;
+  virtual OCTINTERP_API octave_value as_single () const;
 
-  virtual octave_value as_int8 () const;
-  virtual octave_value as_int16 () const;
-  virtual octave_value as_int32 () const;
-  virtual octave_value as_int64 () const;
+  virtual OCTINTERP_API octave_value as_int8 () const;
+  virtual OCTINTERP_API octave_value as_int16 () const;
+  virtual OCTINTERP_API octave_value as_int32 () const;
+  virtual OCTINTERP_API octave_value as_int64 () const;
 
-  virtual octave_value as_uint8 () const;
-  virtual octave_value as_uint16 () const;
-  virtual octave_value as_uint32 () const;
-  virtual octave_value as_uint64 () const;
+  virtual OCTINTERP_API octave_value as_uint8 () const;
+  virtual OCTINTERP_API octave_value as_uint16 () const;
+  virtual OCTINTERP_API octave_value as_uint32 () const;
+  virtual OCTINTERP_API octave_value as_uint64 () const;
 
   virtual octave_base_value * try_narrowing_conversion ()
   { return nullptr; }
 
   virtual void maybe_economize () { }
 
-  virtual Matrix size ();
+  virtual OCTINTERP_API Matrix size ();
 
-  virtual octave_idx_type xnumel (const octave_value_list&);
+  virtual OCTINTERP_API octave_idx_type xnumel (const octave_value_list&);
 
   // FIXME: Do we really need all three of these versions of subsref?
 
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   subsref (const std::string& type,
            const std::list<octave_value_list>& idx);
 
-  virtual octave_value_list
+  virtual OCTINTERP_API octave_value_list
   subsref (const std::string& type,
            const std::list<octave_value_list>& idx,
            int nargout);
 
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   subsref (const std::string& type,
            const std::list<octave_value_list>& idx,
            bool auto_add);
 
-  virtual octave_value_list
+  virtual OCTINTERP_API octave_value_list
   simple_subsref (char type, octave_value_list& idx, int nargout);
 
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   do_index_op (const octave_value_list& idx, bool resize_ok = false);
 
   virtual void assign (const std::string&, const octave_value&) { }
 
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   subsasgn (const std::string& type,
             const std::list<octave_value_list>& idx,
             const octave_value& rhs);
 
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   simple_subsasgn (char type, octave_value_list& idx,
                    const octave_value& rhs);
 
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   undef_subsasgn (const std::string& type,
                   const std::list<octave_value_list>& idx,
                   const octave_value& rhs);
 
-  virtual octave::idx_vector index_vector (bool require_integers = false) const;
+  virtual OCTINTERP_API octave::idx_vector
+  index_vector (bool require_integers = false) const;
 
   virtual dim_vector dims () const { return dim_vector (); }
 
@@ -390,21 +392,23 @@
 
   virtual std::size_t byte_size () const { return 0; }
 
-  virtual octave_idx_type nnz () const;
+  virtual OCTINTERP_API octave_idx_type nnz () const;
 
-  virtual octave_idx_type nzmax () const;
+  virtual OCTINTERP_API octave_idx_type nzmax () const;
 
-  virtual octave_idx_type nfields () const;
+  virtual OCTINTERP_API octave_idx_type nfields () const;
 
-  virtual octave_value reshape (const dim_vector&) const;
+  virtual OCTINTERP_API octave_value reshape (const dim_vector&) const;
 
-  virtual octave_value permute (const Array<int>& vec, bool = false) const;
-
-  virtual octave_value resize (const dim_vector&, bool fill = false) const;
+  virtual OCTINTERP_API octave_value
+  permute (const Array<int>& vec, bool = false) const;
 
-  virtual MatrixType matrix_type () const;
+  virtual OCTINTERP_API octave_value
+  resize (const dim_vector&, bool fill = false) const;
 
-  virtual MatrixType matrix_type (const MatrixType& typ) const;
+  virtual OCTINTERP_API MatrixType matrix_type () const;
+
+  virtual OCTINTERP_API MatrixType matrix_type (const MatrixType& typ) const;
 
   virtual bool is_defined () const { return false; }
 
@@ -464,9 +468,9 @@
 
   virtual bool is_all_va_args () const { return false; }
 
-  virtual octave_value all (int = 0) const;
+  virtual OCTINTERP_API octave_value all (int = 0) const;
 
-  virtual octave_value any (int = 0) const;
+  virtual OCTINTERP_API octave_value any (int = 0) const;
 
   virtual builtin_type_t builtin_type () const { return btyp_unknown; }
 
@@ -555,27 +559,33 @@
 
   virtual void erase_subfunctions () { }
 
-  virtual short int short_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API short int
+  short_value (bool = false, bool = false) const;
 
-  virtual unsigned short int ushort_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API unsigned short int
+  ushort_value (bool = false, bool = false) const;
 
-  virtual int int_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API int
+  int_value (bool = false, bool = false) const;
 
-  virtual unsigned int uint_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API unsigned int
+  uint_value (bool = false, bool = false) const;
 
-  virtual int nint_value (bool = false) const;
+  virtual OCTINTERP_API int nint_value (bool = false) const;
 
-  virtual long int long_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API long int
+  long_value (bool = false, bool = false) const;
 
-  virtual unsigned long int ulong_value (bool = false, bool = false) const;
-
-  virtual int64_t int64_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API unsigned long int
+  ulong_value (bool = false, bool = false) const;
 
-  virtual uint64_t uint64_value (bool = false, bool = false) const;
+  virtual OCTINTERP_API int64_t int64_value (bool = false, bool = false) const;
+
+  virtual OCTINTERP_API uint64_t uint64_value (bool = false, bool = false) const;
 
-  virtual double double_value (bool = false) const;
+  virtual OCTINTERP_API double double_value (bool = false) const;
 
-  virtual float float_value (bool = false) const;
+  virtual OCTINTERP_API float float_value (bool = false) const;
 
   virtual double scalar_value (bool frc_str_conv = false) const
   { return double_value (frc_str_conv); }
@@ -583,110 +593,110 @@
   virtual float float_scalar_value (bool frc_str_conv = false) const
   { return float_value (frc_str_conv); }
 
-  virtual Cell cell_value () const;
+  virtual OCTINTERP_API Cell cell_value () const;
 
-  virtual Matrix matrix_value (bool = false) const;
+  virtual OCTINTERP_API Matrix matrix_value (bool = false) const;
 
-  virtual FloatMatrix float_matrix_value (bool = false) const;
+  virtual OCTINTERP_API FloatMatrix float_matrix_value (bool = false) const;
 
-  virtual NDArray array_value (bool = false) const;
+  virtual OCTINTERP_API NDArray array_value (bool = false) const;
 
-  virtual FloatNDArray float_array_value (bool = false) const;
+  virtual OCTINTERP_API FloatNDArray float_array_value (bool = false) const;
 
-  virtual Complex complex_value (bool = false) const;
+  virtual OCTINTERP_API Complex complex_value (bool = false) const;
 
-  virtual FloatComplex float_complex_value (bool = false) const;
+  virtual OCTINTERP_API FloatComplex float_complex_value (bool = false) const;
 
-  virtual ComplexMatrix complex_matrix_value (bool = false) const;
+  virtual OCTINTERP_API ComplexMatrix complex_matrix_value (bool = false) const;
 
-  virtual FloatComplexMatrix float_complex_matrix_value (bool = false) const;
+  virtual OCTINTERP_API FloatComplexMatrix float_complex_matrix_value (bool = false) const;
 
-  virtual ComplexNDArray complex_array_value (bool = false) const;
+  virtual OCTINTERP_API ComplexNDArray complex_array_value (bool = false) const;
 
-  virtual FloatComplexNDArray float_complex_array_value (bool = false) const;
+  virtual OCTINTERP_API FloatComplexNDArray float_complex_array_value (bool = false) const;
 
-  virtual bool bool_value (bool = false) const;
+  virtual OCTINTERP_API bool bool_value (bool = false) const;
 
-  virtual boolMatrix bool_matrix_value (bool = false) const;
+  virtual OCTINTERP_API boolMatrix bool_matrix_value (bool = false) const;
 
-  virtual boolNDArray bool_array_value (bool = false) const;
+  virtual OCTINTERP_API boolNDArray bool_array_value (bool = false) const;
 
-  virtual charMatrix char_matrix_value (bool force = false) const;
+  virtual OCTINTERP_API charMatrix char_matrix_value (bool force = false) const;
 
-  virtual charNDArray char_array_value (bool = false) const;
+  virtual OCTINTERP_API charNDArray char_array_value (bool = false) const;
 
-  virtual SparseMatrix sparse_matrix_value (bool = false) const;
+  virtual OCTINTERP_API SparseMatrix sparse_matrix_value (bool = false) const;
 
-  virtual SparseComplexMatrix sparse_complex_matrix_value (bool = false) const;
+  virtual OCTINTERP_API SparseComplexMatrix sparse_complex_matrix_value (bool = false) const;
 
-  virtual SparseBoolMatrix sparse_bool_matrix_value (bool = false) const;
+  virtual OCTINTERP_API SparseBoolMatrix sparse_bool_matrix_value (bool = false) const;
 
-  virtual DiagMatrix diag_matrix_value (bool = false) const;
+  virtual OCTINTERP_API DiagMatrix diag_matrix_value (bool = false) const;
 
-  virtual FloatDiagMatrix float_diag_matrix_value (bool = false) const;
+  virtual OCTINTERP_API FloatDiagMatrix float_diag_matrix_value (bool = false) const;
 
-  virtual ComplexDiagMatrix complex_diag_matrix_value (bool = false) const;
+  virtual OCTINTERP_API ComplexDiagMatrix complex_diag_matrix_value (bool = false) const;
 
-  virtual FloatComplexDiagMatrix
+  virtual OCTINTERP_API FloatComplexDiagMatrix
   float_complex_diag_matrix_value (bool = false) const;
 
-  virtual PermMatrix perm_matrix_value () const;
+  virtual OCTINTERP_API PermMatrix perm_matrix_value () const;
 
-  virtual octave_int8 int8_scalar_value () const;
+  virtual OCTINTERP_API octave_int8 int8_scalar_value () const;
 
-  virtual octave_int16 int16_scalar_value () const;
+  virtual OCTINTERP_API octave_int16 int16_scalar_value () const;
 
-  virtual octave_int32 int32_scalar_value () const;
+  virtual OCTINTERP_API octave_int32 int32_scalar_value () const;
 
-  virtual octave_int64 int64_scalar_value () const;
+  virtual OCTINTERP_API octave_int64 int64_scalar_value () const;
 
-  virtual octave_uint8 uint8_scalar_value () const;
+  virtual OCTINTERP_API octave_uint8 uint8_scalar_value () const;
 
-  virtual octave_uint16 uint16_scalar_value () const;
+  virtual OCTINTERP_API octave_uint16 uint16_scalar_value () const;
 
-  virtual octave_uint32 uint32_scalar_value () const;
+  virtual OCTINTERP_API octave_uint32 uint32_scalar_value () const;
 
-  virtual octave_uint64 uint64_scalar_value () const;
+  virtual OCTINTERP_API octave_uint64 uint64_scalar_value () const;
 
-  virtual int8NDArray int8_array_value () const;
+  virtual OCTINTERP_API int8NDArray int8_array_value () const;
 
-  virtual int16NDArray int16_array_value () const;
+  virtual OCTINTERP_API int16NDArray int16_array_value () const;
 
-  virtual int32NDArray int32_array_value () const;
+  virtual OCTINTERP_API int32NDArray int32_array_value () const;
 
-  virtual int64NDArray int64_array_value () const;
+  virtual OCTINTERP_API int64NDArray int64_array_value () const;
 
-  virtual uint8NDArray uint8_array_value () const;
+  virtual OCTINTERP_API uint8NDArray uint8_array_value () const;
 
-  virtual uint16NDArray uint16_array_value () const;
+  virtual OCTINTERP_API uint16NDArray uint16_array_value () const;
 
-  virtual uint32NDArray uint32_array_value () const;
+  virtual OCTINTERP_API uint32NDArray uint32_array_value () const;
 
-  virtual uint64NDArray uint64_array_value () const;
+  virtual OCTINTERP_API uint64NDArray uint64_array_value () const;
 
-  virtual string_vector string_vector_value (bool pad = false) const;
+  virtual OCTINTERP_API string_vector string_vector_value (bool pad = false) const;
 
-  virtual std::string string_value (bool force = false) const;
+  virtual OCTINTERP_API std::string string_value (bool force = false) const;
 
-  virtual Array<std::string> cellstr_value () const;
+  virtual OCTINTERP_API Array<std::string> cellstr_value () const;
 
-  virtual octave::range<double> range_value () const;
+  virtual OCTINTERP_API octave::range<double> range_value () const;
 
   // For now, enable only range<double>.
 
-  virtual octave_map map_value () const;
+  virtual OCTINTERP_API octave_map map_value () const;
 
-  virtual octave_scalar_map scalar_map_value () const;
+  virtual OCTINTERP_API octave_scalar_map scalar_map_value () const;
 
-  virtual string_vector map_keys () const;
+  virtual OCTINTERP_API string_vector map_keys () const;
 
-  virtual bool isfield (const std::string&) const;
+  virtual OCTINTERP_API bool isfield (const std::string&) const;
 
-  virtual std::size_t nparents () const;
+  virtual OCTINTERP_API std::size_t nparents () const;
 
-  virtual std::list<std::string> parent_class_name_list () const;
+  virtual OCTINTERP_API std::list<std::string> parent_class_name_list () const;
 
-  virtual string_vector parent_class_names () const;
+  virtual OCTINTERP_API string_vector parent_class_names () const;
 
   virtual octave_base_value * find_parent_class (const std::string&)
   { return nullptr; }
@@ -697,72 +707,74 @@
   virtual bool is_instance_of (const std::string&) const
   { return false; }
 
-  virtual octave_classdef * classdef_object_value (bool silent = false);
+  virtual OCTINTERP_API octave_classdef * classdef_object_value (bool silent = false);
 
-  virtual octave_function * function_value (bool silent = false);
+  virtual OCTINTERP_API octave_function * function_value (bool silent = false);
 
-  virtual octave_user_function * user_function_value (bool silent = false);
+  virtual OCTINTERP_API octave_user_function * user_function_value (bool silent = false);
 
-  virtual octave_user_script * user_script_value (bool silent = false);
+  virtual OCTINTERP_API octave_user_script * user_script_value (bool silent = false);
 
-  virtual octave_user_code * user_code_value (bool silent = false);
+  virtual OCTINTERP_API octave_user_code * user_code_value (bool silent = false);
 
-  virtual octave_fcn_handle * fcn_handle_value (bool silent = false);
+  virtual OCTINTERP_API octave_fcn_handle * fcn_handle_value (bool silent = false);
 
-  virtual octave_value_list list_value () const;
+  virtual OCTINTERP_API octave_value_list list_value () const;
 
-  virtual octave_value convert_to_str (bool pad = false, bool force = false,
-                                       char type = '\'') const;
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
+  convert_to_str (bool pad = false, bool force = false, char type = '\'') const;
+  virtual OCTINTERP_API octave_value
   convert_to_str_internal (bool pad, bool force, char type) const;
 
-  virtual void convert_to_row_or_column_vector ();
+  virtual OCTINTERP_API void convert_to_row_or_column_vector ();
 
   // The following extractor functions don't perform any implicit type
   // conversions.
 
-  virtual std::string xstring_value () const;
+  virtual OCTINTERP_API std::string xstring_value () const;
 
   virtual bool print_as_scalar () const { return false; }
 
-  virtual void print (std::ostream& os, bool pr_as_read_syntax = false);
+  virtual OCTINTERP_API void
+  print (std::ostream& os, bool pr_as_read_syntax = false);
 
-  virtual void
+  virtual OCTINTERP_API void
   print_raw (std::ostream& os, bool pr_as_read_syntax = false) const;
 
-  virtual bool
+  virtual OCTINTERP_API bool
   print_name_tag (std::ostream& os, const std::string& name) const;
 
-  virtual void
+  virtual OCTINTERP_API void
   print_with_name (std::ostream& output_buf, const std::string& name,
                    bool print_padding = true);
 
   virtual void short_disp (std::ostream& os) const { os << "..."; }
 
-  virtual float_display_format get_edit_display_format () const;
+  virtual OCTINTERP_API float_display_format get_edit_display_format () const;
 
   virtual std::string edit_display (const float_display_format&,
                                     octave_idx_type, octave_idx_type) const
   { return "#VAL"; }
 
-  virtual void print_info (std::ostream& os, const std::string& prefix) const;
+  virtual OCTINTERP_API void
+  print_info (std::ostream& os, const std::string& prefix) const;
 
-  virtual bool save_ascii (std::ostream& os);
+  virtual OCTINTERP_API bool save_ascii (std::ostream& os);
 
-  virtual bool load_ascii (std::istream& is);
+  virtual OCTINTERP_API bool load_ascii (std::istream& is);
 
-  virtual bool save_binary (std::ostream& os, bool save_as_floats);
+  virtual OCTINTERP_API bool save_binary (std::ostream& os, bool save_as_floats);
 
-  virtual bool load_binary (std::istream& is, bool swap,
-                            octave::mach_info::float_format fmt);
+  virtual OCTINTERP_API bool
+  load_binary (std::istream& is, bool swap, octave::mach_info::float_format fmt);
 
-  virtual bool
+  virtual OCTINTERP_API bool
   save_hdf5 (octave_hdf5_id loc_id, const char *name, bool save_as_floats);
 
-  virtual bool
+  virtual OCTINTERP_API bool
   load_hdf5 (octave_hdf5_id loc_id, const char *name);
 
-  virtual int
+  virtual OCTINTERP_API int
   write (octave::stream& os, int block_size,
          oct_data_conv::data_type output_type, int skip,
          octave::mach_info::float_format flt_fmt) const;
@@ -773,28 +785,29 @@
 
   virtual const octave_idx_type * mex_get_jc () const { return nullptr; }
 
-  virtual mxArray * as_mxArray (bool interleaved) const;
+  virtual OCTINTERP_API mxArray * as_mxArray (bool interleaved) const;
 
-  virtual octave_value diag (octave_idx_type k = 0) const;
+  virtual OCTINTERP_API octave_value diag (octave_idx_type k = 0) const;
 
-  virtual octave_value diag (octave_idx_type m, octave_idx_type n) const;
+  virtual OCTINTERP_API octave_value diag (octave_idx_type m, octave_idx_type n) const;
 
-  virtual octave_value sort (octave_idx_type dim = 0,
-                             sortmode mode = ASCENDING) const;
-  virtual octave_value sort (Array<octave_idx_type>& sidx,
-                             octave_idx_type dim = 0,
-                             sortmode mode = ASCENDING) const;
+  virtual OCTINTERP_API octave_value
+  sort (octave_idx_type dim = 0, sortmode mode = ASCENDING) const;
 
-  virtual sortmode issorted (sortmode mode = UNSORTED) const;
+  virtual OCTINTERP_API octave_value
+  sort (Array<octave_idx_type>& sidx, octave_idx_type dim = 0,
+        sortmode mode = ASCENDING) const;
 
-  virtual Array<octave_idx_type>
+  virtual OCTINTERP_API sortmode issorted (sortmode mode = UNSORTED) const;
+
+  virtual OCTINTERP_API Array<octave_idx_type>
   sort_rows_idx (sortmode mode = ASCENDING) const;
 
-  virtual sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
+  virtual OCTINTERP_API sortmode is_sorted_rows (sortmode mode = UNSORTED) const;
 
-  virtual void lock ();
+  virtual OCTINTERP_API void lock ();
 
-  virtual void unlock ();
+  virtual OCTINTERP_API void unlock ();
 
   virtual bool islocked () const { return false; }
 
@@ -802,11 +815,11 @@
 
   virtual void maybe_call_dtor () { }
 
-  virtual octave_value dump () const;
+  virtual OCTINTERP_API octave_value dump () const;
 
-  virtual octave_value storable_value ();
+  virtual OCTINTERP_API octave_value storable_value ();
 
-  virtual octave_base_value * make_storable_value ();
+  virtual OCTINTERP_API octave_base_value * make_storable_value ();
 
   // Standard mappers.  Register new ones here.
   enum unary_mapper_t
@@ -875,26 +888,26 @@
     num_unary_mappers = umap_unknown
   };
 
-  virtual octave_value map (unary_mapper_t) const;
+  virtual OCTINTERP_API octave_value map (unary_mapper_t) const;
 
   // These are fast indexing & assignment shortcuts for extracting
   // or inserting a single scalar from/to an array.
 
   // Extract the n-th element, aka val(n).  Result is undefined if val is not
   // an array type or n is out of range.  Never error.
-  virtual octave_value
+  virtual OCTINTERP_API octave_value
   fast_elem_extract (octave_idx_type n) const;
 
   // Assign the n-th element, aka val(n) = x.  Returns false if val is not an
   // array type, x is not a matching scalar type, or n is out of range.
   // Never error.
-  virtual bool
+  virtual OCTINTERP_API bool
   fast_elem_insert (octave_idx_type n, const octave_value& x);
 
   // This is a helper for the above, to be overridden in scalar types.  The
   // whole point is to handle the insertion efficiently with just *two* VM
   // calls, which is basically the theoretical minimum.
-  virtual bool
+  virtual OCTINTERP_API bool
   fast_elem_insert_self (void *where, builtin_type_t btyp) const;
 
 protected:
@@ -952,7 +965,7 @@
   DECLARE_OV_BASE_TYPEID_FUNCTIONS_AND_DATA
 };
 
-class OCTINTERP_API octave_base_dld_value : public octave_base_value
+class OCTINTERP_TEMPLATE_API octave_base_dld_value : public octave_base_value
 {
 public:
 
--- a/libinterp/octave-value/ov-bool-mat.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-bool-mat.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -52,9 +52,6 @@
 #include "ovl.h"
 #include "oct-hdf5.h"
 #include "ops.h"
-#include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-bool.h"
 #include "ov-bool-mat.h"
 #include "ov-re-mat.h"
@@ -65,8 +62,6 @@
 #include "ls-hdf5.h"
 #include "ls-utils.h"
 
-template class octave_base_matrix<boolNDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_bool_matrix,
                                      "bool matrix", "logical");
 
--- a/libinterp/octave-value/ov-bool-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-bool-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Character matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<boolNDArray>;
+
 class octave_bool_matrix : public octave_base_matrix<boolNDArray>
 {
 public:
--- a/libinterp/octave-value/ov-bool.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-bool.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -42,8 +42,6 @@
 #include "ov-bool.h"
 #include "ov-bool-mat.h"
 #include "ov-base.h"
-#include "ov-base-scalar.h"
-#include "ov-base-scalar.cc"
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
 #include "pr-output.h"
@@ -51,13 +49,6 @@
 #include "ls-oct-text.h"
 #include "ls-hdf5.h"
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_scalar<bool>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_bool, "bool", "logical");
 
 static octave_base_value *
--- a/libinterp/octave-value/ov-bool.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-bool.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Real scalar values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<bool>;
+
 class OCTINTERP_API octave_bool : public octave_base_scalar<bool>
 {
 public:
--- a/libinterp/octave-value/ov-cell.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-cell.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -48,8 +48,6 @@
 #include "oct-hdf5.h"
 #include "unwind-prot.h"
 #include "utils.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-fcn-handle.h"
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
@@ -62,85 +60,6 @@
 #include "ls-hdf5.h"
 #include "ls-utils.h"
 
-// Cell is able to handle octave_value indexing by itself, so just forward
-// everything.
-
-template <>
-octave_value
-octave_base_matrix<Cell>::do_index_op (const octave_value_list& idx,
-                                       bool resize_ok)
-{
-  return m_matrix.index (idx, resize_ok);
-}
-
-template <>
-void
-octave_base_matrix<Cell>::assign (const octave_value_list& idx, const Cell& rhs)
-{
-  m_matrix.assign (idx, rhs);
-}
-
-template <>
-void
-octave_base_matrix<Cell>::assign (const octave_value_list& idx,
-                                  octave_value rhs)
-{
-  // FIXME: Really?
-  if (rhs.iscell ())
-    m_matrix.assign (idx, rhs.cell_value ());
-  else
-    m_matrix.assign (idx, Cell (rhs));
-}
-
-template <>
-void
-octave_base_matrix<Cell>::delete_elements (const octave_value_list& idx)
-{
-  m_matrix.delete_elements (idx);
-}
-
-// FIXME: this list of specializations is becoming so long that we should
-// really ask whether octave_cell should inherit from octave_base_matrix at all.
-
-template <>
-std::string
-octave_base_matrix<Cell>::edit_display (const float_display_format&,
-                                        octave_idx_type i,
-                                        octave_idx_type j) const
-{
-  octave_value val = m_matrix(i, j);
-
-  std::string tname = val.type_name ();
-  const dim_vector& dv = val.dims ();
-  std::string dimstr = dv.str ();
-  return "[" + dimstr + " " + tname + "]";
-}
-
-template <>
-octave_value
-octave_base_matrix<Cell>::fast_elem_extract (octave_idx_type n) const
-{
-  if (n < m_matrix.numel ())
-    return Cell (m_matrix(n));
-  else
-    return octave_value ();
-}
-
-template <>
-bool
-octave_base_matrix<Cell>::fast_elem_insert (octave_idx_type n,
-    const octave_value& x)
-{
-  const octave_cell *xrep = dynamic_cast<const octave_cell *> (&x.get_rep ());
-
-  bool retval = xrep && xrep->m_matrix.numel () == 1 && n < m_matrix.numel ();
-  if (retval)
-    m_matrix(n) = xrep->m_matrix(0);
-
-  return retval;
-}
-
-template class octave_base_matrix<Cell>;
 
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_cell, "cell", "cell");
 
--- a/libinterp/octave-value/ov-cell.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-cell.h	Sun Jan 21 19:34:01 2024 +0100
@@ -46,6 +46,8 @@
 
 // Cells.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<Cell>;
+
 class octave_cell : public octave_base_matrix<Cell>
 {
 public:
--- a/libinterp/octave-value/ov-ch-mat.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-ch-mat.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -48,15 +48,10 @@
 #include "unistr-wrappers.h"
 
 #include "mxarray.h"
-#include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-ch-mat.h"
 #include "errwarn.h"
 #include "pr-output.h"
 
-template class octave_base_matrix<charNDArray>;
-
 octave::idx_vector
 octave_char_matrix::index_vector (bool /* require_integers */) const
 {
@@ -324,7 +319,7 @@
         std::size_t output_length = in_m.numel ();                             \
         charNDArray ch_array = charNDArray (in_m.dims ());                     \
         const uint8_t *in = reinterpret_cast<const uint8_t *> (in_m.data ());  \
-        uint8_t *buf = reinterpret_cast<uint8_t *> (ch_array.rwdata ());  \
+        uint8_t *buf = reinterpret_cast<uint8_t *> (ch_array.rwdata ());       \
         U8_FCN (in, m_matrix.numel (), nullptr, buf, &output_length);          \
         if (output_length != static_cast<std::size_t> (m_matrix.numel ()))     \
           {                                                                    \
--- a/libinterp/octave-value/ov-ch-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-ch-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Character matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<charNDArray>;
+
 class octave_char_matrix : public octave_base_matrix<charNDArray>
 {
 protected:
--- a/libinterp/octave-value/ov-complex.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-complex.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -43,8 +43,6 @@
 #include "ov-complex.h"
 #include "ov-flt-complex.h"
 #include "ov-base.h"
-#include "ov-base-scalar.h"
-#include "ov-base-scalar.cc"
 #include "ov-cx-mat.h"
 #include "ov-scalar.h"
 #include "errwarn.h"
@@ -54,14 +52,6 @@
 #include "ls-oct-text.h"
 #include "ls-hdf5.h"
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-extern template class octave_base_scalar<FloatComplex>;
-
-template class octave_base_scalar<Complex>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_complex,
                                      "complex scalar", "double");
 
--- a/libinterp/octave-value/ov-complex.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-complex.h	Sun Jan 21 19:34:01 2024 +0100
@@ -47,6 +47,8 @@
 
 // Complex scalar values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<Complex>;
+
 class OCTINTERP_API octave_complex : public octave_base_scalar<Complex>
 {
 public:
--- a/libinterp/octave-value/ov-cx-mat.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-cx-mat.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -50,8 +50,6 @@
 #include "oct-stream.h"
 #include "ops.h"
 #include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-complex.h"
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
@@ -65,8 +63,6 @@
 #include "ls-utils.h"
 
 
-template class octave_base_matrix<ComplexNDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_complex_matrix,
                                      "complex matrix", "double");
 
--- a/libinterp/octave-value/ov-cx-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-cx-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Complex matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<ComplexNDArray>;
+
 class OCTINTERP_API octave_complex_matrix : public octave_base_matrix<ComplexNDArray>
 {
 public:
--- a/libinterp/octave-value/ov-float.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-float.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -46,8 +46,6 @@
 #include "ov-scalar.h"
 #include "ov-float.h"
 #include "ov-base.h"
-#include "ov-base-scalar.h"
-#include "ov-base-scalar.cc"
 #include "ov-flt-re-mat.h"
 #include "ov-typeinfo.h"
 #include "pr-output.h"
@@ -59,8 +57,6 @@
 #include "ls-hdf5.h"
 
 
-template class octave_base_scalar<float>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_float_scalar, "float scalar",
                                      "single");
 
--- a/libinterp/octave-value/ov-float.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-float.h	Sun Jan 21 19:34:01 2024 +0100
@@ -49,6 +49,8 @@
 
 // Real scalar values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<float>;
+
 class OCTINTERP_API octave_float_scalar : public octave_base_scalar<float>
 {
 public:
--- a/libinterp/octave-value/ov-flt-complex.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-flt-complex.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -40,9 +40,6 @@
 #include "oct-stream.h"
 #include "ops.h"
 #include "ov-complex.h"
-#include "ov-base.h"
-#include "ov-base-scalar.h"
-#include "ov-base-scalar.cc"
 #include "ov-flt-cx-mat.h"
 #include "ov-float.h"
 #include "ov-flt-complex.h"
@@ -53,13 +50,6 @@
 #include "ls-oct-text.h"
 #include "ls-hdf5.h"
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<float>;
-
-template class octave_base_scalar<FloatComplex>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_float_complex,
                                      "float complex scalar", "single");
 
--- a/libinterp/octave-value/ov-flt-complex.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-flt-complex.h	Sun Jan 21 19:34:01 2024 +0100
@@ -47,6 +47,8 @@
 
 // Complex scalar values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<FloatComplex>;
+
 class OCTINTERP_API octave_float_complex : public octave_base_scalar<FloatComplex>
 {
 public:
--- a/libinterp/octave-value/ov-flt-cx-mat.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-flt-cx-mat.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -50,8 +50,6 @@
 #include "oct-stream.h"
 #include "ops.h"
 #include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-complex.h"
 #include "ov-flt-complex.h"
 #include "ov-cx-mat.h"
@@ -69,8 +67,6 @@
 #include "ls-utils.h"
 
 
-template class octave_base_matrix<FloatComplexNDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_float_complex_matrix,
                                      "float complex matrix", "single");
 
--- a/libinterp/octave-value/ov-flt-cx-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-flt-cx-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Complex matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<FloatComplexNDArray>;
+
 class OCTINTERP_API octave_float_complex_matrix : public octave_base_matrix<FloatComplexNDArray>
 {
 public:
--- a/libinterp/octave-value/ov-flt-re-mat.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-flt-re-mat.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -63,8 +63,6 @@
 #include "oct-stream.h"
 #include "ops.h"
 #include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-scalar.h"
 #include "ov-float.h"
 #include "ov-flt-complex.h"
@@ -84,8 +82,6 @@
 #include "ls-hdf5.h"
 
 
-template class octave_base_matrix<FloatNDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_float_matrix, "float matrix",
                                      "single");
 
--- a/libinterp/octave-value/ov-flt-re-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-flt-re-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Real matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<FloatNDArray>;
+
 class OCTINTERP_API octave_float_matrix : public octave_base_matrix<FloatNDArray>
 {
 public:
--- a/libinterp/octave-value/ov-int16.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-int16.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-int16.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_int16_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_int16_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<int16NDArray>;
-
-template class octave_base_int_matrix<int16NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int16_matrix,
                                      "int16 matrix", "int16");
 
-template class octave_base_scalar<octave_int16>;
-
-template class octave_base_int_scalar<octave_int16>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int16_scalar,
                                      "int16 scalar", "int16");
--- a/libinterp/octave-value/ov-int32.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-int32.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-int32.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_int32_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_int32_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<int32NDArray>;
-
-template class octave_base_int_matrix<int32NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int32_matrix,
                                      "int32 matrix", "int32");
 
-template class octave_base_scalar<octave_int32>;
-
-template class octave_base_int_scalar<octave_int32>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int32_scalar,
                                      "int32 scalar", "int32");
--- a/libinterp/octave-value/ov-int64.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-int64.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-int64.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_int64_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_int64_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<int64NDArray>;
-
-template class octave_base_int_matrix<int64NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int64_matrix,
                                      "int64 matrix", "int64");
 
-template class octave_base_scalar<octave_int64>;
-
-template class octave_base_int_scalar<octave_int64>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int64_scalar,
                                      "int64 scalar", "int64");
--- a/libinterp/octave-value/ov-int8.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-int8.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-int8.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_int8_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_int8_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<int8NDArray>;
-
-template class octave_base_int_matrix<int8NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int8_matrix,
                                      "int8 matrix", "int8");
 
-template class octave_base_scalar<octave_int8>;
-
-template class octave_base_int_scalar<octave_int8>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_int8_scalar,
                                      "int8 scalar", "int8");
--- a/libinterp/octave-value/ov-intx.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-intx.h	Sun Jan 21 19:34:01 2024 +0100
@@ -49,6 +49,8 @@
 #include "ov-re-mat.h"
 #include "ov-scalar.h"
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_int_matrix<intNDArray<OCTAVE_INT_T>>;
+
 class OCTINTERP_API OCTAVE_VALUE_INT_MATRIX_T
   : public octave_base_int_matrix<intNDArray<OCTAVE_INT_T>>
 {
@@ -384,7 +386,11 @@
   DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
 };
 
-class OCTINTERP_API OCTAVE_VALUE_INT_SCALAR_T
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_int_scalar<OCTAVE_INT_T>;
+
+class
+OCTINTERP_API
+OCTAVE_VALUE_INT_SCALAR_T
   : public octave_base_int_scalar<OCTAVE_INT_T>
 {
 public:
--- a/libinterp/octave-value/ov-re-mat.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-re-mat.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -63,8 +63,6 @@
 #include "oct-stream.h"
 #include "ops.h"
 #include "ov-base.h"
-#include "ov-base-mat.h"
-#include "ov-base-mat.cc"
 #include "ov-scalar.h"
 #include "ov-re-mat.h"
 #include "ov-flt-re-mat.h"
@@ -85,8 +83,6 @@
 #include "ls-hdf5.h"
 
 
-template class octave_base_matrix<NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_matrix, "matrix", "double");
 
 static octave_base_value *
--- a/libinterp/octave-value/ov-re-mat.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-re-mat.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Real matrix values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_matrix<NDArray>;
+
 class OCTINTERP_API octave_matrix : public octave_base_matrix<NDArray>
 {
 public:
--- a/libinterp/octave-value/ov-scalar.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-scalar.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -46,8 +46,6 @@
 #include "ov-scalar.h"
 #include "ov-float.h"
 #include "ov-base.h"
-#include "ov-base-scalar.h"
-#include "ov-base-scalar.cc"
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
 #include "pr-output.h"
@@ -59,13 +57,6 @@
 #include "ls-oct-text.h"
 #include "ls-hdf5.h"
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<float>;
-
-template class octave_base_scalar<double>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_scalar, "scalar", "double");
 
 static octave_base_value *
--- a/libinterp/octave-value/ov-scalar.h	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-scalar.h	Sun Jan 21 19:34:01 2024 +0100
@@ -48,6 +48,8 @@
 
 // Real scalar values.
 
+extern template class OCTINTERP_EXTERN_TEMPLATE_API octave_base_scalar<double>;
+
 class OCTINTERP_API octave_scalar : public octave_base_scalar<double>
 {
 public:
--- a/libinterp/octave-value/ov-uint16.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-uint16.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -46,8 +46,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-uint16.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -60,21 +58,8 @@
 octave_hdf5_id octave_uint16_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_uint16_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<uint16NDArray>;
-
-template class octave_base_int_matrix<uint16NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint16_matrix,
                                      "uint16 matrix", "uint16");
 
-template class octave_base_scalar<octave_uint16>;
-
-template class octave_base_int_scalar<octave_uint16>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint16_scalar,
                                      "uint16 scalar", "uint16");
--- a/libinterp/octave-value/ov-uint32.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-uint32.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-uint32.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_uint32_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_uint32_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<uint32NDArray>;
-
-template class octave_base_int_matrix<uint32NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint32_matrix,
                                      "uint32 matrix", "uint32");
 
-template class octave_base_scalar<octave_uint32>;
-
-template class octave_base_int_scalar<octave_uint32>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint32_scalar,
                                      "uint32 scalar", "uint32");
--- a/libinterp/octave-value/ov-uint64.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-uint64.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-uint64.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_uint64_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_uint64_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<uint64NDArray>;
-
-template class octave_base_int_matrix<uint64NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint64_matrix,
                                      "uint64 matrix", "uint64");
 
-template class octave_base_scalar<octave_uint64>;
-
-template class octave_base_int_scalar<octave_uint64>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint64_scalar,
                                      "uint64 scalar", "uint64");
--- a/libinterp/octave-value/ov-uint8.cc	Fri Apr 05 19:57:54 2024 +0200
+++ b/libinterp/octave-value/ov-uint8.cc	Sun Jan 21 19:34:01 2024 +0100
@@ -45,8 +45,6 @@
 #  define HDF5_SAVE_TYPE 0
 #endif
 
-#include "ov-base-int.h"
-#include "ov-base-int.cc"
 #include "ov-uint8.h"
 #include "pr-output.h"
 #include "variables.h"
@@ -59,21 +57,8 @@
 octave_hdf5_id octave_uint8_matrix::s_hdf5_save_type = HDF5_SAVE_TYPE;
 octave_hdf5_id octave_uint8_scalar::s_hdf5_save_type = HDF5_SAVE_TYPE;
 
-// Prevent implicit instantiations on some systems (Windows, others?)
-// that can lead to duplicate definitions of static data members.
-
-extern template class octave_base_scalar<double>;
-
-template class octave_base_matrix<uint8NDArray>;
-
-template class octave_base_int_matrix<uint8NDArray>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint8_matrix,
                                      "uint8 matrix", "uint8");
 
-template class octave_base_scalar<octave_uint8>;
-
-template class octave_base_int_scalar<octave_uint8>;
-
 DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_uint8_scalar,
                                      "uint8 scalar", "uint8");