Ann: SWI-Prolog 9.3.31

Dear SWI-Prolog user,

Hard work continues after the Alain Colmerauer prize :slight_smile: The idea is to
iron away most issues that result from the migration of the GUI tools
and then release 9.4.0. Release 9.3.31 is the next candidate. I do
not plan big changes before 9.4.0, i.e., you may consider this a
release candidate. This release fixes several small
issues and removes most of the now obsolete code from the source
repository.

Enjoy --- Jan

SWI-Prolog Changelog since version 9.3.30

  • DOC: Update most links to swipl-win and related functionality

  • PORT: Replace incomplete function pointer types by void* C11 and
    later do not allow for foreign_t (*function)().

  • CLEANUP: Delete obolete components - snap build instructions -
    packages/swipl-win (Qt console) - Various files supporting this.

  • CLEANUP: Deletes Qt console.

  • CLEANUP: Remove old swipl-win.exe code.

  • PORT: Carefully detect that git is the sane thing on MacOS.
    With help from @ridgeworks

  • FIXED: Update library(threadutil) for Epilog support.

  • STYLE: dark theme: avoid navy_blue color for global predicates.

  • ENHANCED: Allow set_stream(S, alias(user_input)) without locking S.

  • CLEANUP: Synchronise handling of the tty_control flag between Windows
    and Unix. Needs further cleanup, notably a separate definition of
    the indexes for the boolean flags.

  • MODIFIED: Moved enabling ansi colors on the Windows console to be
    used only with tty control.

  • CLEANUP: Remove non-functioning PL_wait_for_console_input() This
    fixes Windows console input without the commandline editor.

  • FIXED: Handle command line argument --foreign=copy

  • FIXED: qsave_program/2 determinism.

  • FIXED: Parse -<base>'<digits> Reported by Joachim Schimpf. Thanks.

  • MODIFIED: MacOS: change default working dir of the app to ~/Prolog
    ~/Documents is subject to TCC (Transparency, Consent, and Control),
    showing a confirm dialog on any file access until we get SWI-Prolog
    signed.

  • DOC: clarify the use of Key and Priority in library(heaps)

Package xpce

  • MODIFIED: Control the Prolog consoles using a single predictate
    set_epilog/1.

  • ADDED: epilog_attach/1 to attach an epilog window to an already running
    thread. This now supports attach_console/0,1 from library(threadutil).

2 Likes

A minor complaint about the Windows version: If I type halt., nothing happens, i.e., the program is not closed. Instead, the prompt returns. I can, of course, close the program with the menu (but then I need to search for the mouse etc.

Desk mess

Yes. Not entirely sure what should happen, but surely something. The normal way is to type Ctrl-D, the (default POSIX) end-of-file. When started as swipl-win, the first console is the main console. Terminating that stops Prolog if there are no other open windows and asks what to do if there are other windows. We can make halt/0 halt the entire process regardless of the terminal it was entered or just do the same as Ctrl-D, i.e., terminate the thread it is executed in an the associated console. What would be best?

Oh, I wasn’t aware of Ctrl-D. That works fine, thanks. [And maybe no need to change halt’s behavior]

That is why I had not noticed :slight_smile: Still, text books talk about halt/0, so it should do something sensible. As is, it throws an exception that cannot be caught normally. That is currently ignored by the toplevel.

For now, resolved using FIXED: When a REPL loop receives the halt/0,1 exception, make it return. ¡ SWI-Prolog/swipl-devel@94a45df ¡ GitHub Comments on the desired behaviour is still welcome.

On a “standard” Ubuntu linux, I get some messages from test_installation

%c': got 'Thu Jul 13 12:34:10 2006', expected 'Thu Jul 13 14:34:10 2006'
'%X': got '12:34:10', expected '14:34:10'
'%H': got '12', expected '14'
'%I': got '12', expected '02'
'%k': got '12', expected '14'
'%l': got '12', expected ' 2'
'%r': got '12:34:10 PM', expected '02:34:10 PM'
'%R': got '12:34', expected '14:34'
'%T': got '12:34:10', expected '14:34:10'
'%z': got '+0000', expected '+0200'
'%Z': got 'CET', expected 'CEST'
'%+': got 'Thu Jul 13 12:34:10 2006', expected 'Thu Jul 13 14:34:10 2006'

In test.pl, the time zone is set to CET, and if I change this to CEST, the message with %Z disappears. But that is not a real solution.

That is a bit odd. This all runs silently for me. Default time is set using /etc/localtime, which is a link to /usr/share/zoneinfo/Europe/Amsterdam. The strange thing is that running e.g.,

TZ=GMT swipl ../tests/library/test_date.pl

still makes the tests succeed!? I’m a little surprised. Where does /etc/localtime point to on your machine? Is TZ set? If I understand things correctly, setting TZ causes the system to load /usr/share/zoneinfo/$TZ. If not set it loads /etc/localtime

Note that you can run the test, printing all output using e.g.,

TZ=GMT src/swipl ../tests/library/test_date.pl
?- run_tests(all, [format(log), output(always)]).

Unclear what is going on. This works fine,

TZ=GMT src/swipl ../tests/library/test_date.pl
?- run_tests(all, [format(log), output(always)]).

Whereas ~/swipl/bin/swipl and then test_installation report the mismatch.

All this happens regardless of TZ and /etc/timezone. FWIW, /etc/timezone was a little text file on my system, not a symbolic link. I changed it to point to /usr/share/zoneinfo/Europe/Amsterdam, with no effect.

Can you give me some hint on how to proceed? It’s not important, though.

I have little clue. The only difference I can see is that test.pl uses

setenv('TZ', 'CET').

Otherwise it just loads and runs the test files. If, after ?- test_installation., you run

 ?- test_date:test_format.

Does the problem persist? If so, all I can suggest is to carefully examine flags and environment variables. You can also try to run the test isolated in the installed environment using

 bin/swipl lib/swipl/test/library/test_date.pl
 ?- test_date.

Hmm. The problem does reproduce on one of the SWI-Prolog cloud servers running Ubuntu 22.04. And, it reproduces normally on the compiled system rather than only in test_installation/0. And this fixes the problem:

TZ=Europe/Amsterdam src/swipl ../tests/library/test_date.pl
?- test_date.

As well as

 TZ=CET src/swipl ../tests/library/test_date.pl

I wonder whether setting the timezone in test.pl is too late? Could you try setting it as above?

Without setting the environment variable:

$ cd swipl
$ bin/swipl lib/swipl/test/library/test_date.pl
?- test_date. % Problem
?- test_date:test_format. % Problem
?- test_installation. % Problem
?- halt.

Amsterdam

$ TZ=Europe/Amsterdam bin/swipl lib/swipl/test/library/test_date.pl
?- test_date. % ok
?- test_date:test_format. % ok
?- test_installation. % Problem!
?- test_date. % Problem!
?- getenv('TZ', TZ).
TZ = 'CET'. % from test_installation I guess

CEST

$ TZ=CEST bin/swipl lib/swipl/test/library/test_date.pl
?- test_date. % Problem! Just one line disappeared, namely: '%Z': got 'CET', expected 'CEST'

Now look at this admittedly random site in the internet: https://stackoverflow.com/questions/17360599/how-do-i-set-tz-env-var-to-cet-in-visual-c

$ TZ=CET-1CEST,M3.5.0/2,M10.5.0/3 bin/swipl lib/swipl/test/library/test_date.pl
?- test_date. % ok

I changed test.pl accordingly, now the test passes without messages.

:- setenv('TZ', 'CET-1CEST,M3.5.0/2,M10.5.0/3').

Of course, we can also change it to

:- setenv('TZ', 'Europe/Amsterdam'). % 🍃

It is a bit unfortunate that this side effect cannot be reversed after the tests have been invoked, at least that is what the comment says.

% The  test-suite  library/test_date.pl  depends  on  the  timezone.  As
% correct results are only  provided  for   the  CET  (Central European)
% timezone we use this. Timezone cannot be  changed at runtime, so we do
% this early.

But with respect to the Colmerauer price that you recently received, that side effect is in order :slight_smile:

One more thing: some of the unit tests generate files in the current folder, which is not always writable. Would you mind a PR that redirects these to a temporary folder? It might take some time, though.

That would certainly be an improvement. On the other hand, as long as we make sure the tests are executed in suitable directory, there is not a problem. Normally they are run by ctest that executes them in the build directory. Maybe you can control that the working directory is a temporary directory? Probably we can do this in test_installation/0: check that the working directory is writeable. If not, create a dir in the tmp directory and use working_directory/2 to move there?

I’ll give it a try. Meanwhile, a new minor problem appeared, test_installation needs swipl to be invoked with an absolute file name. So, this works:

$ /usr/local/bin/swipl
?- test_installation.

This does not:

$ cd /usr/local
$ bin/swipl
?- test_installation.

Edit: (That is wrong: The problem occurs in predicates like me(Me) that determine the name of the file and then use that information e.g. to create a saved state. Let’s see if that can be fixed. I vaguely remember that it’s actually not as trivial to expand argv[0].) The problem occurs in cwd arguments of process_create. That can easily be fixed.

Works fine for Linux as long as the working directory is writeable. me/1 uses the executable flag, which is AFAIK an absolute path. Anway, I’m sure you’ll figure it out :slight_smile:

Haha, greetings from deep down the rabbit hole. The obvious solution is a temporary file. Now, tmp_file/2 is considered unsafe, so I use tmp_file_stream/3, like this:

state_output(State) :-
    current_prolog_flag(windows, true),
    tmp_file_stream(State, Stream, [encoding(binary), extension('.exe')]),
    close(Stream).

state_output(State) :-
    tmp_file_stream(State, Stream, [encoding(binary)]),
    close(Stream).

I only need the file name to hand it over to the swipl child process that actually creates the state with process_create/3. Is this safe to close the stream immediately after creating the temporary file? I guess so.

Now, tmp_file_stream/3 deletes the file at Prolog exit, which is not always wanted (e.g., when debugging is turned on). So the next question is: shouldn’t tmp_file_stream/3 get an additional option, atexit(keep) or atexit(delete)? Delete would be default. Such a flag might be useful in other contexts, too.

Like this:

state_output(State) :-
    current_prolog_flag(windows, true),
    tmp_file_stream(State, Stream, [encoding(binary), extension('.exe'), atexit(keep)]),
    close(Stream).

state_output(State) :-
    tmp_file_stream(State, Stream, [encoding(binary), atexit(keep)]),
    close(Stream).

(the file is deleted anyway, since test_saved_states.pl uses setup_call_cleanup/3).

It may not be that simple. AFAIK, modern operating systems tend to deny running executables from the temporary file area.

tmp_file_stream/3 is not any better than tmp_file/2 here. The call exists to atomically create a file and have it opened in exclusive mode, so nobody can temper with it. As you close it, this is no good.

One way out may be to still use temporary files, but run them using swipl <exe>. That of course fails to test that the created executable is indeed executable.

Can’t we just limit the context in which test_installation/0 is executed? Possibly by checking the context is fine?

I feared it.

Yes of course. The “current directory” of the windows version is c:\program files\swipl though, so that would block test_installation/0. Which would be a bit of a pity.

Hi

On Ubuntu Linux the Emacs window stops responding when the main thread is sleeping.

To reproduce:

Start swipl, start emacs, run sleep/1 on main console then try to select something in Emacs.

$ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 9.3.31-40-gaa4dd464b)

…

?- emacs.
true.

?- sleep(30).
true.

“org.swi_prolog.swipl-win” Is Not Responding

That is unfortunately unavoidable. Well, it is probably avoidable for sleep/1. In general though, the GUI is not responsive if you use swipl and have a running query. GUI event dispatching is only integrated into reading from the terminal. That is the consequence of using the SDL library, which can only run in the main thread.

If you want full profit of the GUI, run swipl-win. Then the GUI runs in the main thread and the Prolog toplevel runs in con1 (or con2, … if you open multiple consoles).

These days I normally use swipl-win as my default Prolog application during development.