Minimum library versions for 0.21(1.0?) dev cycle

I guess it’s time to revisit this discussion (here’s the one from 0.20). For 0.20 we pegged our minimum supported versions to Ubuntu 18.04 LTS. That version will be at its standard 5-year end-of-life in just a few months here, so one possibility for 0.21/1.0 is that we bump our oldest supported version for compilation purposes to Ubuntu 20.04 LTS. Of course this doesn’t affect Snap/AppImage/Binary distribution, etc.

That would mean the following software versions as the oldest supported:

  • GCC 10 (C++17 with some C++20 features)
  • CMake 3.16
  • Python 3.8
  • Qt 5.12

Is our minimal supported MSVC also supporting C++17?

Yes, we require C++17 already for 0.20 – I think it’s unlikely that we will decide to require C++20, I just point out that some features (e.g. operator <=>) have been available since GCC 10, so we could conceivably use them.

GCC 10 (C++17 with some C++20 features)

What about clang? Is there also a version for C++17 that supports C++20 features?

As discussed here, the CMake minimal version should be 3.12: https://forum.freecadweb.org/viewtopic.php?p=629047#p629047

Are there any arguments against this?

Is there a reason not to go to 3.16?

wmayer are you ready for us to make this set of requirements changes on master? There is a PR in updating cMake, and I’ve got some use for Python 3.8 features.

Some weeks ago I have setup a system with Debian Buster where all libraries have been upgraded to a fairly recent version. However, I also wanted to prepare a Xubuntu 22.04 and hadn’t have the time so far to do it. Would it be OK to postpone this for another week, i.e. between Christmas and Sylvester?

Btw, should we already move to C++20, too?

JFYI, I encounter lot of issues on 22.04 due to incompatibilities between pivy and Python 3.10.
I’ll eventually build latest pivy release to see if issues are solved there.

Yes, no problem postponing it – I’ll ping you again after Christmas.

Btw, should we already move to C++20, too?

I’d be thrilled to (C++20 brings a lot of really great improvements, it’s a massive upgrade), but technically Ubuntu 20.04 LTS only has GCC 10, which doesn’t fully support C++20 (though I think it probably has most of the stuff we’d want to use immediately – the major exception is Modules, which is going to take us a very long time to move to!). We have to be careful with which features we actually use: https://gcc.gnu.org/projects/cxx-status.html

I have not myself tested enabling C++20 in CMake on a GCC 10 system, I don’t know what happens when you do so.

Sorry I missed this earlier: I believe that 20.04 LTS also has clang-10, which offers most of C++20.

I’d be thrilled to (C++20 brings a lot of really great improvements, it’s a massive upgrade), but technically Ubuntu 20.04 LTS only has GCC 10, which doesn’t fully support C++20 (though I think it probably has most of the stuff we’d want to use immediately

The feature I would like to use is std::format and its variants. Using std::format would allow us to get rid of any printf-like functions and use the type-safe replacement. In case this is not supported yet then an alternative is using the fmt library.

the major exception is Modules, which is going to take us a very long time to move to

That’s anyway no point for me at the moment.

Sorry I missed this earlier: I believe that 20.04 LTS also has clang-10, which offers most of C++20.

OK, but developers should have the option to choose between gcc and clang.

I don’t think any of the compilers in Ubuntu 20.04 LTS have support for std::format (at least, that’s what Stack Overflow tells me!):
https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.2020
https://libcxx.llvm.org/Status/Cxx20.html

I don’t think any of the compilers in Ubuntu 20.04 LTS have support for std::format (at least, that’s what Stack Overflow tells me!):

OK, thanks for checking it!

Yes, no problem postponing it – I’ll ping you again after Christmas.

I have (almost) finished setting up my brand new Xubuntu 22.04.

I don’t think any of the compilers in Ubuntu 20.04 LTS have support for std::format (at least, that’s what Stack Overflow tells me!):

OK, then it’s best to stay at C++17 for now and use the fmt library in the meantime.

JFYI, I encounter lot of issues on 22.04 due to incompatibilities between pivy and Python 3.10.
I’ll eventually build latest pivy release to see if issues are solved there.

Now I get dozens of these errors, too. I will try the latest pivy version from master to see if it fixes the issue.

In order to build a pivy Debian package with the fixes from master for 22.04 follow these steps:

dpkg-source -x pivy_0.6.5-1build6.dsc

This will extract the archive and apply the patches.

  • Open a graphical diff tool like meld and compare the master with the extracted pivy sources and copy over the relevant changes.

dpkg-source --commit


and follow the instructions
* debuild
* Install the newly created Debian package python3-pivy_0.6.5-1build6_amd64.deb

After installing the package all pivy errors are gone.

Hint: If you use another Debian derivative then the procedure is almost the same. You only have to make sure to get the .dsc, original source tarball and Debian patch file that match with your OS version.
\
\
If you are unsure of what changes to apply from master here is my patch file:

```text
Description: <short summary of the patch>
 TODO: Put a short summary on the line above and replace this paragraph
 with a longer explanation of this change. Complete the meta-information
 with other relevant fields (see below for details). To make it easier, the
 information below has been extracted from the changelog. Adjust it or drop
 it.
 .
 pivy (0.6.5-1build6) jammy; urgency=medium
 .
   * No-change rebuild with Python 3.10 only
Author: Graham Inggs <ginggs@ubuntu.com>

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: https://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: 2022-12-31

--- pivy-0.6.5.orig/Inventor/fields/SoMFVec2f.i
+++ pivy-0.6.5/Inventor/fields/SoMFVec2f.i
@@ -39,7 +39,7 @@ convert_SoMFVec2f_array(PyObject * input
 
 /* free the list */
 %typemap(freearg) const float xy[][2] {
-  if($1) delete[] $1;
+  if($1) free($1);
 }
 
 %typemap(in) const float xy[2] (float temp[2]) {
--- pivy-0.6.5.orig/Inventor/fields/SoMFVec3d.i
+++ pivy-0.6.5/Inventor/fields/SoMFVec3d.i
@@ -39,7 +39,7 @@ convert_SoMFVec3d_array(PyObject * input
 
 /* free the list */
 %typemap(freearg) const double xyz[][3] {
-  if ($1) { delete[] $1; }
+  if ($1) { free($1); }
 }
 
 %typemap(in) const double xyz[3] (double temp[3]) {
--- pivy-0.6.5.orig/Inventor/fields/SoMFVec3f.i
+++ pivy-0.6.5/Inventor/fields/SoMFVec3f.i
@@ -39,9 +39,10 @@ convert_SoMFVec3f_array(PyObject * input
 
 /* free the list */
 %typemap(freearg) const float xyz[][3] {
-  if ($1) { delete[] $1; }
+  if ($1) { free($1); }
 }
 
+
 %typemap(in) const float xyz[3] (float temp[3]) {
   convert_SbVec3f_array($input, temp);
   $1 = temp;
--- pivy-0.6.5.orig/Inventor/fields/SoMFVec4f.i
+++ pivy-0.6.5/Inventor/fields/SoMFVec4f.i
@@ -39,7 +39,7 @@ convert_SoMFVec4f_array(PyObject * input
 
 /* free the list */
 %typemap(freearg) const float xy[][2] {
-  if ($1) { delete[] $1; }
+  if ($1) { free($1); }
 }
 
 %typemap(in) const float xyzw[4] (float temp[4]) {
--- pivy-0.6.5.orig/Inventor/nodekits/SoBaseKit.i
+++ pivy-0.6.5/Inventor/nodekits/SoBaseKit.i
@@ -2,6 +2,8 @@
 %extend SoBaseKit {
 %pythoncode %{
     def __getattr__(self,name):
+       if name == 'this':
+          return SoNode.__getattr__(self,name)
        c = _coin.SoBaseKit_getNodekitCatalog(self)
        if c.getPartNumber(name) >= 0:
            part = self.getPart(name,1)
--- pivy-0.6.5.orig/interfaces/coin.i
+++ pivy-0.6.5/interfaces/coin.i
@@ -28,6 +28,10 @@ applications."
 // https://stackoverflow.com/questions/40959436/swig-python-detected-a-memory-leak-of-type-uint32-t-no-destructor-found
 %include "stdint.i"
 
+%begin %{
+#define PY_SSIZE_T_CLEAN
+%}
+
 %{
 #if defined(_WIN32) || defined(__WIN32__)
 #include <windows.h>
@@ -95,15 +99,11 @@ if (init_file_emulator() < 0) {
 */
 
 %pythoncode %{        
-for x in list(locals()):
-  value = locals()[x]
-  try:
-    if isinstance(value, type) and issubclass(value, SoFieldContainer):
-      for name in list(value.__dict__):
-        val = value.__dict__[name]
-        if isinstance(val, property):
-          delattr(value, name)
-  except NameError:
-    # value == SoSearchAction_duringSearchAll ???
-    pass
-%}
\ No newline at end of file
+for key in list(locals()):
+  x = locals()[key]
+  if isinstance(x, type) and issubclass(x, SoFieldContainer):
+    for name in list(x.__dict__):
+      thing = x.__dict__[name]
+      if isinstance(thing, property):
+        delattr(x, name)
+%}
--- pivy-0.6.5.orig/interfaces/coin_header_includes.h
+++ pivy-0.6.5/interfaces/coin_header_includes.h
@@ -352,6 +352,7 @@
 #include <Inventor/misc/SoGLBigImage.h>
 #include <Inventor/misc/SoGLImage.h>
 #include <Inventor/misc/SoGlyph.h>
+#include <Inventor/misc/SoGeo.h>
 #include <Inventor/misc/SoLightPath.h>
 #include <Inventor/misc/SoNormalGenerator.h>
 #include <Inventor/misc/SoNotification.h>
@@ -404,6 +405,10 @@
 #include <Inventor/nodes/SoFile.h>
 #include <Inventor/nodes/SoFont.h>
 #include <Inventor/nodes/SoFontStyle.h>
+#include <Inventor/nodes/SoGeoCoordinate.h>
+#include <Inventor/nodes/SoGeoLocation.h>
+#include <Inventor/nodes/SoGeoOrigin.h>
+#include <Inventor/nodes/SoGeoSeparator.h>
 #include <Inventor/nodes/SoGroup.h>
 #include <Inventor/nodes/SoImage.h>
 #include <Inventor/nodes/SoIndexedFaceSet.h>
--- pivy-0.6.5.orig/interfaces/pivy_common_typemaps.i
+++ pivy-0.6.5/interfaces/pivy_common_typemaps.i
@@ -28,19 +28,12 @@ typedef int Py_ssize_t;
   #define IS_PY3K
 #endif
 
-/* a casting helper function */
-SWIGEXPORT PyObject *
-cast(PyObject * self, PyObject * args)
+PyObject *
+cast_internal(PyObject * self, PyObject * obj, const char * type_name, Py_ssize_t type_len)
 {
   swig_type_info * swig_type = 0;
   void * cast_obj = 0;
-  char * type_name, * ptr_type;
-  int type_len;
-  PyObject * obj = 0;
-
-  if (!PyArg_ParseTuple(args, "Os#:cast", &obj, &type_name, &type_len)) {
-    SWIG_fail;
-  }
+  char * ptr_type;
 
   /*
    * add a pointer sign to the string coming from the interpreter
@@ -74,7 +67,24 @@ cast(PyObject * self, PyObject * args)
   if (SWIG_arg_fail(1)) { SWIG_fail; }
 
   return SWIG_NewPointerObj((void*)cast_obj, swig_type, 0);
-  fail:
+fail:
+  return NULL;
+}
+
+/* a casting helper function */
+SWIGEXPORT PyObject *
+cast(PyObject * self, PyObject * args)
+{
+  char * type_name;
+  Py_ssize_t type_len;
+  PyObject * obj = 0;
+
+  if (!PyArg_ParseTuple(args, "Os#:cast", &obj, &type_name, &type_len)) {
+    SWIG_fail;
+  }
+
+  return cast_internal(self, obj, type_name, type_len);
+fail:
   return NULL;
 }
 
@@ -86,18 +96,15 @@ autocast_base(SoBase * base)
 
   /* autocast the result to the corresponding type */
   if (base && base->isOfType(SoFieldContainer::getClassTypeId())) {
-    PyObject * cast_args = NULL;
     PyObject * obj = NULL;
     SoType type = base->getTypeId();
 
     /* in case of a non built-in type get the closest built-in parent */
     while (!(type.isBad() || result)) {
       obj = SWIG_NewPointerObj((void*)base, SWIGTYPE_p_SoBase, 0);
-      cast_args = Py_BuildValue("(Os)", obj, type.getName().getString());
       
-      result = cast(NULL, cast_args);
+      result = cast_internal(NULL, obj, type.getName().getString(), type.getName().getLength());
 
-      Py_DECREF(cast_args);
       Py_DECREF(obj);
 
       if (!result) { type = type.getParent(); }
@@ -120,18 +127,15 @@ autocast_path(SoPath * path)
   
   /* autocast the result to the corresponding type */
   if (path) {
-    PyObject * cast_args = NULL;
     PyObject * obj = NULL;
     SoType type = path->getTypeId();
 
     /* in case of a non built-in type get the closest built-in parent */
     while (!(type.isBad() || result)) {
       obj = SWIG_NewPointerObj((void*)path, SWIGTYPE_p_SoPath, 0);
-      cast_args = Py_BuildValue("(Os)", obj, type.getName().getString());
       
-      result = cast(NULL, cast_args);
+      result = cast_internal(NULL, obj, type.getName().getString(), type.getName().getLength());
 
-      Py_DECREF(cast_args);
       Py_DECREF(obj);
 
       if (!result) { type = type.getParent(); }
@@ -154,18 +158,15 @@ autocast_field(SoField * field)
 
   /* autocast the result to the corresponding type */
   if (field) {
-    PyObject * cast_args = NULL;
     PyObject * obj = NULL;
     SoType type = field->getTypeId();
 
     /* in case of a non built-in type get the closest built-in parent */
     while (!(type.isBad() || result)) {
       obj = SWIG_NewPointerObj((void*)field, SWIGTYPE_p_SoField, 0);
-      cast_args = Py_BuildValue("(Os)", obj, type.getName().getString());
       
-      result = cast(NULL, cast_args);
+      result = cast_internal(NULL, obj, type.getName().getString(), type.getName().getLength());
 
-      Py_DECREF(cast_args);
       Py_DECREF(obj);
       
       if (!result) { type = type.getParent(); }
@@ -188,18 +189,15 @@ autocast_event(SoEvent * event)
   
   /* autocast the result to the corresponding type */
   if (event) {
-    PyObject * cast_args = NULL;
     PyObject * obj = NULL;
     SoType type = event->getTypeId();
 
     /* in case of a non built-in type get the closest built-in parent */
     while (!(type.isBad() || result)) {
       obj = SWIG_NewPointerObj((void*)event, SWIGTYPE_p_SoEvent, 0);
-      cast_args = Py_BuildValue("(Os)", obj, type.getName().getString());
       
-      result = cast(NULL, cast_args);
+      result = cast_internal(NULL, obj, type.getName().getString(), type.getName().getLength());
 
-      Py_DECREF(cast_args);
       Py_DECREF(obj);
 
       if (!result) { type = type.getParent(); }
--- pivy-0.6.5.orig/interfaces/soqt.i
+++ pivy-0.6.5/interfaces/soqt.i
@@ -23,6 +23,9 @@ otherwise it will fall back to regular S
 
 %module(package="pivy.gui", docstring=SOQT_MODULE_DOCSTRING) soqt
 
+%begin %{
+#define PY_SSIZE_T_CLEAN
+%}
 
 %{
 /*
--- pivy-0.6.5.orig/pivy/graphics/__init__.py
+++ pivy-0.6.5/pivy/graphics/__init__.py
@@ -93,6 +93,7 @@ class Object3D(coin.SoSeparator):
     def drag_objects(self):
         if self.enabled:
             return [self]
+        return []
 
     def delete(self):
         if self.enabled and not self._delete:
@@ -454,4 +455,4 @@ class InteractionSeparator(coin.SoSepara
             else:
                 self.static_objects.append(child)
         else:
-            super(InteractionSeparator, self).addChild(child) 
\ No newline at end of file
+            super(InteractionSeparator, self).addChild(child)

I have filed Launchpad bug 2000840 with patches attached to fix pivy in Ubuntu 22.04. (You can vote for this bug here.)

You can vote for this bug here.

Done.

Done

Fix released for pivy package in Ubuntu 22.04 LTS (and Ubuntu 22.10).
https://bugs.launchpad.net/ubuntu/+source/pivy/+bug/2000840