Ann: SWI-Prolog 8.5.5

Dear SWI-Prolog user,

SWI-Prolog 8.5.5 is ready for download. Most of the patches address
portability issues and some regression that resulted from more use of
color and hyperlinking on modern terminals. Highlights:

  • Security issue (loading init.pl from current directory).
  • Allow suspend/yield from foreign code. After discussion with
    @maren.
  • Several enhancement to print_term/2 (print big terms with
    layout). Both fixes (invalid output), better handling of
    terms with operators that exceed the line width, dynamic
    detection of the console width, etc.
  • Extend library(apply_macros) to expand maplist calls with
    a small compile-time known list to a conjunction of calls.
  • Fixes to read/1 and friends for postfix operators (@keke)

And of course the usual list of small enhancements and fixes.

Enjoy --- Jan

SWI-Prolog Changelog since version 8.5.4

  • TEST: Started a few operator tests

  • FIXED: handling postfix operators must reduce the left side before
    reducing the postfix operator.

  • ENHANCED: Issue#24: clause_info/4: reject if term layout returned
    by expand_term/4 is bogus. This forces the guitracer to revert
    to decompiling.

  • FIXED: arg xf xf (cascading postfix operators) where the priority
    of the first is higher than the second must generate a syntax error
    rather than an incorrect term.

  • DEBUG: Fixed duplicate debug id

  • FIXED: print_term/2 handling of postfix operators.

  • SECURITY: running plain swipl loads init.pl from the current
    directory if this file exists. It is not advised to load customisation
    files from the current directory. We now only load init.pl when
    explicitly called using swipl -f init.pl while an implicit init
    file is only loaded from the user_app_config path alias.

  • ENHANCED: library(apply_macros) now expands maplist calls with lists
    known at compile time into a sequence of calls if this is safe and
    the lists are at most 10 elements long.

  • ADDED: copy_term/4 and copy_term_nat/4. These predicates provide a
    partial renaming of variables and is used in s(CASP). This patch also
    improves out-of-memory handling and adds a test suit for copy_term.

  • DOC: foreach/2 by @swi

  • FIXED: pack_rebuild/1 if the pack is installed but does not provide
    binaries for the current architecture. @nicos.

  • FIXED: SWISH Issue#146: failure to render stacktrace due to failure
    of message_to_string/2 on ansi(Style, Fmt, Arg) if Arg is not a list.

  • ADDED: PL_can_yield() to figure out whether the current execution
    context allows for yielding control.

  • DOC: foreign yield interface

  • ADDED: Allow yield/resume from foreign predicates.

  • MODIFIED: Query identifiers now keep track of the engine to which they
    are associated. As a result, they are now anonymous pointers rather
    than (pointer wide) integers. Does not affect compatibility except
    source compatibility when the value is combined with integral types.

  • BUILD: Disable MQI if multi-threading is not enabled.

  • FIXED: print_term/2 from entering a loop. Also fixes unneeded
    parenthesis in lists.

  • FIXED: finding clauses from a source location could crash on thread
    local predicates

  • FIXED: conjunction/disjunction.

  • FIXED: print_term/2: respect write options when computing with of
    native output.

  • MODIFIED: print_term/2 to get the default right margin from tty_size
    if the output is a tty and tty_size/2 succeeds.

  • ENHANCED: mkconj/3 and mkdisj/3 to produces a right-grouped term, e.g.
    ?- mkconj((a,b),c, Conj) Conj = (a,b,c)

    (was Conj = ((a,b),c)).

  • FIXED: We must preserve the pack registration when creating a saved
    state to make loading foreign resources work.

  • ENHANCED: main/0 to avoid setting up application signal handling and
    termination when run interactively.

  • FIXED: Issue#917: separate S_DYNAMIC and S_MULTIFILE. Jos de Roo.

  • ADDED: print_term/2: options fullstop(Boolean) and nl(Bool). Also lots
    of documentation restyling and removed old conditional compilation.

  • ENHANCED: print_term/2 to deal with operator expressions that exceed
    the line width.

  • FIXED: print_term/2: max priority of list elements and compound term
    arguments to 999 to force parenthesis.

  • FIXED: Issue#917: WAM Table mismatch: wam_table[119(s_static)] ==
    wam_table[124(s_multifile)]

  • SNAP: Reverted to core20 because Qt is broken on core20.

  • FIXED: Ensure VMI instruction are on unique addresses. This patch
    extends 7bf463db4dcc7b4e27c820ef8fc6f94fd8116720 for the case that
    two VMIs jump to the same real implementation.

  • SNAP: Trying to switch to core20 base. See
    Old version of fontconfig Ā· Issue #67 Ā· octave-snap/octave-snap Ā· GitHub

  • PORT: Guarantee two VM instructions are not optimized to use the
    same code.

  • FIXED: Ensure bigints are properly indexed on 32-bit platforms.

Package http

  • FIXED: Handle ansi(Style, Fmt, Args), url(Pos) and url(URL, Label)
    message line elements when formulating an HTTP response.

Package jpl

  • CLEANUP: Type correctness in debug messages.

  • COMPAT: Allow qid_t to be an opaque pointer.

Package pengines

  • FIXED: Pengine emulation of tab/1 to accept an expression.

Package ssl

  • PORT: Fix build on OpenBSD 7.0 using LibreSSL LibreSSL 3.4.0 made
    struct ssl_session_st opaque.

Package xpce

  • FIXED: GUI tracer: avoid instantiation error. Kwon-Young Choi.

  • FIXED: Allow the Prolog Navigator to work with zero-arity compounds.

1 Like

Starting with 8.5.4 (support for M1 Apple silicon), the development releases of the MacOS bundle no longer run on OSā€™s prior to Mojave (10.14). Is this a real requirement that will persist for future releases, or is it a target configuration issue that could possibly be changed to permit the Intel binary piece to be run on earlier OSā€™s? (I suspect Mojave is required to recognize the fat binary file format.)

According to macOS | endoflife.date, the oldest supported version of MacOS is 10.15 (Catalina). MacOS 10.14 is required for Qt 6, which is required because Qt 5 doesnā€™t support the M1.

As a result Iā€™ve updated the minimum version for all dependencies for the binary package to 10.14.

If you have an older version I guess updating is a good idea. If you do not want that, Macports can probably be used to compile from source.

More recent versions of MacOS break some older applications and I also have hardware dependency issues impeding an OS upgrade, so guess I have some hard decisions to make. Not relishing the possibility of building from source on a regular basis; is Building SWI-Prolog on MacOSX up-to-date for this purpose?

Sadly, Appleā€™s support periods for macOS are relatively short, and upgrading to a newer supported version is not always an option. For example, 10.14 (Mojave) is a little over three years old and already out of support. macOS 10.15 (Catalina) and later no longer support 32-bit applications, so users who rely on such software cannot easily upgrade from 10.14.

Additionally, macOS 10.14 requires a Mac from at least 2012 or so, so the SWI-Prolog binaries donā€™t work on Macs older than about 10 years. Thatā€™s not a terribly strict requirement, but still less than whatā€™s needed on other systems. For example, the Windows binaries only need Windows 7, which came out in 2009 and runs on systems many years older than that.

I suppose you could build the Intel slice against Qt 5 to get around the 10.14 requirement? ARM is only supported starting with macOS 11 anyway, so building that against Qt 6 isnā€™t an issue. Or alternatively you could use Qt 6, but build SWI itself with a 10.12 deployment target as before - that way the Qt GUI would require 10.14, but all other parts of SWI should continue to work on older versions.

I would recommend trying MacPorts first, as suggested by Jan - Iā€™ve had good experiences with it myself. MacPorts takes care of installing all the necessary dependencies - it uses pre-built binaries where available, but will automatically fall back to building from source where necessary. It works quite well on older macOS versions as well (they even still have some support for Mac OS X 10.4 and PowerPC!).

That said, building from source is not that bad either. Especially once you have the build environment set up and working, updating SWI only requires git pull && git submodule update --init && cmake --build builddir.

1 Like

That is a serious problem for anyone buying an Apple. IMO it is these days not a great idea to connect a computer with an unsupported OS to the internet. This makes such a machine rather useless. You can install both Windows and Linux on your old Apple hardware AFAIK :slight_smile:

Anyway, the number of downloads of the MacOS binary package doesnā€™t really justify setting up a separate distribution for older Intel Macs. Anyone is free to do so. It probably just works from the current source.

Most Apple users seem to go with Homebrew or Macports for installing the usual bunch of open source development tools. Homebrew seems more popular, but unfortunately Iā€™ve never managed to get a recipe for SWI-Prolog accepted that provides the full user experience. The Macports version works great and a new Portfile is updated with every development release.

Looks pretty much ok.

Note that you can also build with just Appleā€™s xCode bundle (providing Appleā€™s clang C compiler). The file scripts/macos-deps.sh documents building the dependencies from source. Donā€™t expect it to just run. It probably needs some guidance and should be considered more documentation that a script :frowning:

Iā€™m a little confused. If I just:

port install swi-prolog-devel

what do I get? I.e., do the rest of the instructions just deal with a customization of the full configuration?

If you just want to install and use SWI normally, then port install swi-prolog-devel is enough. The rest of the instructions are for manually building from source, so you can ignore them unless you want to modify SWI.

You might still have to install Xcode though, if you havenā€™t already. For some dependencies, MacPorts doesnā€™t have pre-compiled binaries (especially for older macOSes), and in that case you need to have Xcode installed so that MacPorts can build those components.

Indeed. Not sure exactly how, but Iā€™ve managed to build 8.5.5 via this route; it ends up in /opt/local, which isnā€™t obvious from the instructions. However, I really would like the app bundle with the qt window equivalent to whatā€™s available via SWI-Prolog downloads.

If you want to build the Qt console it becomes a little harder. First of all you need to download and install Qt, in your case Qt5 as Qt6 doesnā€™t work on older Macs. Second, you need to add the directory holding the Qt development binaries to $PATH. Typically that is something like

 .../Qt/5.something/macos/bin

Then you need to build yourself using the normal build instructions the POSIX/Unix systems after installing the dependencies using Macports. After building you should have the app that you can run from the build directory using this command

 SWI_HOME_DIR=`pwd`/home open packages/swipl-win/swipl-win.app

Iā€™m not really sure how to properly install this. One route is to create the installer. To to that, add -DBUILD_MACOS_BUNDLE=ON to the cmake flags. After building, run cpack in the build directory. That should create the bundle disk image that you can normally install.

I havenā€™t tried it, but wouldnā€™t it be easier to install Qt via MacPorts as well? Then you donā€™t have to change any paths by hand, and itā€™s also easier to uninstall if you donā€™t need Qt anymore.

Is there any particular reason why the MacPorts version of SWI doesnā€™t include the Qt app? MacPorts has no trouble installing GUI apps, although GUI apps are less commonly packaged in MacPorts than CLI tools.

1 Like

I donā€™t know. It surely works without all these trouble on Linux where, after installing Qt from the package manager the normal installation simply adds swipl-win as executable. I barely ever use it. I prefer terminator, surely after the hyperlink additions proposed by @swi. Still looking for something remotely comparable on the Mac :frowning:

Too hard for me. Iā€™m happy with using an old release for general development and a MacPorts version for specific test purposes (if required).

As an aside, the stable release I generally use runs about 50% faster than my MacPorts 8.5.5 version, so thereā€™s probably some compiler configuration magic that isnā€™t happening somewhere.

We now build universal binaries and gcc isnā€™t yet reliable on Apple M1, so we use Appleā€™s clang compiler which produces less efficient binaries :frowning: Macs are a lot of trouble :frowning: The Apple M1 is a great piece of hardware though: silent, low energy consumption and remarkably fast.

Although it sounds like thereā€™s a price to be paid if youā€™re using Intel. To be honest, CPUā€™s got fast enough for my purposes more than ten years ago.

Unfortunately port install swi-prolog and port install swi-prolog-devel both fail due to issues with db53 and hamcrest-core failing to build (on an Apple M1).

Following the instructions here: https://www.swi-prolog.org/build/macos.txt Iā€™m able to install all of the dependencies except for hamcrest-core.

Yes. That is happening for some time on various MacOS versions. I hoped these packages would be fixed upstream, but that doesnā€™t seem to happen :frowning: hamcrest-core is only needed for the JPL tests, so we can drop that. db53 is a different issue. If there is another version of the BerkeleyDB package that works properly under MacOS we could move to that. How to find out? If not we could delete the dependency which would drop library(bdb). I have no clue how many people use it.

Dear Jan,

I am currently preparing an R package (rolog) that embeds a dll with swipl, I guess you remember since I repeatedly share my experience on this forum :slight_smile: . Before uploading to CRAN (repository for R add-ons), contributors are asked to do a

R CMD check --as-cran rolog_1.0.tar.gz

with the package source. This step produces warnings about pragmas

* checking pragmas in C/C++ headers and code ... WARNING
Files which contain pragma(s) suppressing important diagnostics
  ā€˜src/swipl-devel/packages/xpce/src/ker/goodies.cā€™
  ā€˜src/swipl-devel/packages/xpce/src/win/window.cā€™
Files which contain pragma(s) suppressing diagnostics:
  ā€˜src/swipl-devel/packages/clib/mallocinfo.cā€™
  ā€˜src/swipl-devel/packages/ssl/ssl4pl.cā€™

and another one in pl-thread.c which is not shown here because I removed the lines in the code to see what happens. As far as I have heard, chances are low to get a CRAN package accepted if R CMD check produces warnings, so I am wondering if thereā€™s a way to get rid of the pragmas.

I had a look at these pragmas to, well, kinda, ā€œcheckā€ if they are still needed. The system is a WSL2 ubuntu, most recent version, gcc 11.2.0, so everything below is obviously specific for my computer.

  1. pl-thread.c (not shown above because I have already removed it)

This is the code (line 1891+)

#if __GNUC__ == 11
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif
    pthread_cleanup_push(free_prolog_thread, info->thread_data);
#if __GNUC__  == 11
#pragma GCC diagnostic pop
#endif

The pragma has been inserted a few months ago to suppress a ā€œfalse positiveā€ warning, google search indicates that there has been discussion whether itā€™s really false positive. I have to add: I lack the knowledge to really understand what the people are talking about in these discussions.

I have disabled the pragma, no warning, so the problem seems to have gone (on my computer). My suggestion: remove the pragma until someone complains (unlikely, since the only effect is a warning)

  1. The pragma in xpce/ker/goodies.c (line 891f and around 1160)
#if !(defined(HAVE_VSSCANF) && defined(HAVE_CAST_VA_LIST))
#define NO_VSSCANF 1
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-security"
#endif

I removed the pragma, recompiled with XPCE enabled and got this warning for the zero argument case:

/home/matthias/rolog/src/swipl-devel/packages/xpce/src/ker/goodies.c: In function ā€˜scanstrā€™:
/home/matthias/rolog/src/swipl-devel/packages/xpce/src/ker/goodies.c:1006:3: warning: format not a string literal and no format arguments [-Wformat-security]
 1006 |   { case 0:     ar = sscanf(str, fmt); break;
      |   ^

The case refers to a situation in which there is no argument to be parsed, so I replaced the line by

  switch(argn)
  { case 0: ar = 0 ; break;
    case 1: ar = sscanf(str, fmt, ptrs[0]); break;

and the warning disappeared. Itā€™s interesting, though, that on my system, vsscanf does not seem to be accessible, but that is unrelated to the pragma. Suggestion: remove the pragma and fix the case distinction

  1. xpce/win/window.c (line 704)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
  if ( sw->focus != (Graphical) sw || notNil(sw->focus_recogniser) )
  { rval = send(sw, NAME_event, ev, EAV);
  }
#pragma GCC diagnostic pop

I donā€™t understand this one. I removed the pragma, recompiled swipl under Windows (Rtools42 compiler) with xpce enabled, but there wasnā€™t any warning. Suggestion: remove the pragma until someone complains

  1. Next one, clib/mallocinfo.c
#ifdef HAVE_MALLINFO
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
static foreign_t
pl_malinfo(term_t stats)
{ term_t tail = PL_copy_term_ref(stats);
  struct mallinfo info = mallinfo();

  addNameInteger(tail, "arena",    (unsigned)info.arena);
  addNameInteger(tail, "ordblks",  (unsigned)info.ordblks);
  addNameInteger(tail, "hblks",    (unsigned)info.hblks);
  addNameInteger(tail, "hblkhd",   (unsigned)info.hblkhd);
  addNameInteger(tail, "uordblks", (unsigned)info.uordblks);
  addNameInteger(tail, "fordblks", (unsigned)info.fordblks);
  addNameInteger(tail, "keepcost", (unsigned)info.keepcost);

  return PL_unify_nil(tail);
}
#pragma GCC diagnostic pop

Disabling the pragma raises a warning,

[ 78%] Building C object packages/clib/CMakeFiles/plugin_mallocinfo.dir/mallocinfo.c.o
/home/matthias/rolog/src/swipl-devel/packages/clib/mallocinfo.c: In function ā€˜pl_malinfoā€™:
/home/matthias/rolog/src/swipl-devel/packages/clib/mallocinfo.c:74:10: warning: ā€˜mallinfoā€™ is deprecated [-Wdeprecated-declarations]
   74 |   struct mallinfo info = mallinfo();
      |          ^~~~~~~~
In file included from /home/matthias/rolog/src/swipl-devel/packages/clib/mallocinfo.c:39:
/usr/include/malloc.h:113:24: note: declared here
  113 | extern struct mallinfo mallinfo (void) __THROW __MALLOC_DEPRECATED;
      |                        ^~~~~~~~

From /usr/include/mallinfo.h it appears that this can be fixed by switching to the mallinfo2 structure that uses size_t instead of ā€œintā€ for its members.

  • A quick fix is to use mallinfo2, that is struct mallinfo2 info = mallinfo2(); and just change the check for HAVE_MALLINFO to HAVE_MALLINFO2 in src/config.h.cmake and cmake/Config.cmake. The only thing that is lost is memory allocation info in 32-bit-Systems, that would be skipped.
  • An improved fix would also change addNameInteger to addNameInt64, which is also rather easy to do.
  1. Last one, src/swipl-devel/packages/ssl/ssl4pl.c

That one is hidden in macOS code, so I cannot do anything. Moreover, it is for SSL, and I would not want to touch security stuff.

@jan, Iā€™ll make a few PRs for 1-4, would you consider them? To be clear, the pragmas mentioned above just suppress warnings, so the worst thing that can happen is a few people seeing warnings on their compiler log.

I just added one more. The policy is to get 100% clean compilation on the current main development environments for the platforms for which we produce binaries. On older or less commonly used platforms we accept some false positive warnings. The idea is that mistakes during development are not overlooked. If we get a new compiler version there are typically some warnings. These are examined and avoided. In some (rare) cases this means a real fix, sometimes a bit cleaner way to write the same, sometimes cheating by initializing a variable that is claimed to be possibly uninitialized (try to avoid that) and as a last resort we use #pragma. Ideally weā€™d get rid of the work-arounds required for older compilers that are no longer needed. That is a lot of work :frowning:

GCC 11.0 was pretty noisy. If some of the false positives are fixed with GCC 11.2 Iā€™m happy to drop those pragmas. It seems unlikely we get rid of all of them though. I just silenced deprecated vfork() on MacOS. There is an explanation why we want to keep using vfork() for some scenarios in the docs for process_set_method/1. The SSL one is a similar case where CMake checks the function is there, dropping some functionality weā€™d rather not drop :frowning:

So, if R requires the code to have no pragmas we have a problem. Do R packages allow for a patch file that allows you to remove the remaining ones?

1 Like